Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3470 → Rev 3471

/branches/tracing/kernel/generic/include/ipc/ipc_kbox.h
File deleted
/branches/tracing/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/tracing/kernel/generic/src/console/cmd.c
398,17 → 398,17
.argc = 0
};
 
/* Data and methods for 'ipc_task' command */
static int cmd_ipc_task(cmd_arg_t *argv);
static cmd_arg_t ipc_task_argv = {
/* Data and methods for 'ipc' command */
static int cmd_ipc(cmd_arg_t *argv);
static cmd_arg_t ipc_argv = {
.type = ARG_TYPE_INT,
};
static cmd_info_t ipc_task_info = {
.name = "ipc_task",
.description = "ipc_task <taskid> Show IPC information of given task.",
.func = cmd_ipc_task,
static cmd_info_t ipc_info = {
.name = "ipc",
.description = "ipc <taskid> Show IPC information of given task.",
.func = cmd_ipc,
.argc = 1,
.argv = &ipc_task_argv
.argv = &ipc_argv
};
 
/* Data and methods for 'zone' command */
461,7 → 461,7
&uptime_info,
&halt_info,
&help_info,
&ipc_task_info,
&ipc_info,
&set4_info,
&slabs_info,
&symaddr_info,
937,7 → 937,7
*
* return Always 1
*/
int cmd_ipc_task(cmd_arg_t * argv) {
int cmd_ipc(cmd_arg_t * argv) {
ipc_print_task(argv[0].intval);
return 1;
}
/branches/tracing/kernel/generic/src/ipc/ipc_kbox.c
File deleted
/branches/tracing/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/tracing/kernel/generic/src/ipc/sysipc.c
42,10 → 42,9
#include <ipc/sysipc.h>
#include <ipc/irq.h>
#include <ipc/ipcrsc.h>
#include <ipc/ipc_kbox.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>
823,7 → 822,8
 
ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
 
atomic_dec(&TASK->active_calls);
if (!(call->flags & IPC_CALL_DISCARD_ANSWER))
atomic_dec(&TASK->active_calls);
 
if (call->flags & IPC_CALL_DISCARD_ANSWER) {
ipc_call_free(call);
899,7 → 899,7
if (rc != 0)
return (unative_t) rc;
 
printf("sys_ipc_connect_kbox(%lld, %d)\n", taskid_arg.value);
LOG("sys_ipc_connect_kbox(%" PRIu64 ")\n", taskid_arg.value);
 
return ipc_connect_kbox(taskid_arg.value);
#else
/branches/tracing/kernel/generic/src/ipc/ipc.c
43,7 → 43,7
#include <synch/waitq.h>
#include <synch/synch.h>
#include <ipc/ipc.h>
#include <ipc/ipc_kbox.h>
#include <ipc/kbox.h>
#include <errno.h>
#include <mm/slab.h>
#include <arch.h>
573,7 → 573,8
(call->flags & IPC_CALL_NOTIF));
ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC));
atomic_dec(&TASK->active_calls);
if (!(call->flags & IPC_CALL_DISCARD_ANSWER))
atomic_dec(&TASK->active_calls);
ipc_call_free(call);
}
}
/branches/tracing/kernel/generic/src/udebug/udebug_ipc.c
33,9 → 33,11
/**
* @file
* @brief Udebug IPC message handling.
*
* This module handles udebug IPC messages and calls the appropriate
* functions from the udebug_ops module which implement them.
*/
#include <print.h>
#include <proc/task.h>
#include <proc/thread.h>
#include <arch.h>
116,6 → 118,13
return 0;
}
 
/** Process a BEGIN call.
*
* Initiates a debugging session for the current task. The reply
* to this call may or may not be sent before this function returns.
*
* @param call The call structure.
*/
static void udebug_receive_begin(call_t *call)
{
int rc;
127,6 → 136,10
return;
}
 
/*
* If the initialization of the debugging session has finished,
* send a reply.
*/
if (rc != 0) {
IPC_SET_RETVAL(call->data, 0);
ipc_answer(&TASK->kernel_box, call);
133,6 → 146,11
}
}
 
/** Process an END call.
*
* Terminates the debugging session for the current task.
* @param call The call structure.
*/
static void udebug_receive_end(call_t *call)
{
int rc;
143,6 → 161,11
ipc_answer(&TASK->kernel_box, call);
}
 
/** Process a SET_EVMASK call.
*
* Sets an event mask for the current debugging session.
* @param call The call structure.
*/
static void udebug_receive_set_evmask(call_t *call)
{
int rc;
156,13 → 179,16
}
 
 
/** Process a GO call.
*
* Resumes execution of the specified thread.
* @param call The call structure.
*/
static void udebug_receive_go(call_t *call)
{
thread_t *t;
int rc;
 
//printf("debug_go()\n");
 
t = (thread_t *)IPC_GET_ARG2(call->data);
 
rc = udebug_go(t, call);
173,13 → 199,16
}
}
 
/** Process a STOP call.
*
* Suspends execution of the specified thread.
* @param call The call structure.
*/
static void udebug_receive_stop(call_t *call)
{
thread_t *t;
int rc;
 
printf("debug_stop()\n");
 
t = (thread_t *)IPC_GET_ARG2(call->data);
 
rc = udebug_stop(t, call);
187,6 → 216,11
ipc_answer(&TASK->kernel_box, call);
}
 
/** Process a THREAD_READ call.
*
* Reads the list of hashes of the (userspace) threads in the current task.
* @param call The call structure.
*/
static void udebug_receive_thread_read(call_t *call)
{
unative_t uspace_addr;
237,6 → 271,11
ipc_answer(&TASK->kernel_box, call);
}
 
/** Process an ARGS_READ call.
*
* Reads the argument of a current syscall event (SYSCALL_B or SYSCALL_E).
* @param call The call structure.
*/
static void udebug_receive_args_read(call_t *call)
{
thread_t *t;
334,7 → 373,11
ipc_answer(&TASK->kernel_box, call);
}
 
 
/** Process an MEM_READ call.
*
* Reads memory of the current (debugged) task.
* @param call The call structure.
*/
static void udebug_receive_mem_read(call_t *call)
{
unative_t uspace_dst;
391,10 → 434,10
}
 
 
/**
* Handle a debug call received on the kernel answerbox.
/** Handle a debug call received on the kernel answerbox.
*
* This is called by the kbox servicing thread.
* This is called by the kbox servicing thread. Verifies that the sender
* is indeed the debugger and calls the appropriate processing function.
*/
void udebug_call_receive(call_t *call)
{
/branches/tracing/kernel/generic/src/udebug/udebug.c
32,8 → 32,10
 
/**
* @file
* @brief Udebug.
* @brief Udebug hooks and data structure management.
*
* Udebug is an interface that makes userspace debuggers possible.
*
* 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
48,7 → 50,7
*/
#include <synch/waitq.h>
#include <print.h>
#include <debug.h>
#include <udebug/udebug.h>
#include <errno.h>
#include <arch.h>
63,6 → 65,11
atomic_dec(&THREAD->udebug.int_lock);
}
 
/** Initialize udebug part of task structure.
*
* Called as part of task structure initialization.
* @param ut Pointer to the structure to initialize.
*/
void udebug_task_init(udebug_task_t *ut)
{
mutex_initialize(&ut->lock, MUTEX_PASSIVE);
72,6 → 79,11
ut->evmask = 0;
}
 
/** Initialize udebug part of thread structure.
*
* Called as part of thread structure initialization.
* @param ut Pointer to the structure to initialize.
*/
void udebug_thread_initialize(udebug_thread_t *ut)
{
mutex_initialize(&ut->lock, MUTEX_PASSIVE);
90,6 → 102,14
ut->cur_event = 0; /* none */
}
 
/** Wait for a GO message.
*
* When a debugging event occurs in a thread or the thread is stopped,
* this function is called to block the thread until a GO message
* is received.
*
* @param wq The wait queue used by the thread to wait for GO messages.
*/
static void udebug_wait_for_go(waitq_t *wq)
{
int rc;
105,10 → 125,13
 
/** 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.
* 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.
*
* @return True if the thread was in a debugging session when the function
* checked, false otherwise.
*/
static bool udebug_thread_precheck(void)
{
121,6 → 144,16
return res;
}
 
/** Start of stoppable section.
*
* A stoppable section is a section of code where if the thread can be stoped. In other words,
* if a STOP operation is issued, the thread is guaranteed not to execute
* any userspace instructions until the thread is resumed.
*
* Having stoppable sections is better than having stopping points, since
* a thread can be stopped even when it is blocked indefinitely in a system
* call (whereas it would not reach any stopping point).
*/
void udebug_stoppable_begin(void)
{
int nsc;
189,6 → 222,11
mutex_unlock(&TASK->udebug.lock);
}
 
/** End of a stoppable section.
*
* This is the point where the thread will block if it is stopped.
* (As, by definition, a stopped thread must not leave its stoppable section).
*/
void udebug_stoppable_end(void)
{
/* Early check for undebugged tasks */
259,6 → 297,11
udebug_int_unlock();
}
 
/** Syscall event hook.
*
* Must be called before and after servicing a system call. This generates
* a SYSCALL_B or SYSCALL_E event, depending on the value of @a end_variant.
*/
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)
323,6 → 366,14
udebug_int_unlock();
}
 
/** Thread-creation event hook.
*
* Must be called when a new userspace thread is created in the debugged
* task. Generates a THREAD_B event.
*
* @param t Structure of the thread being created. Not locked, as the
* thread is not executing yet.
*/
void udebug_thread_b_event(struct thread *t)
{
call_t *call;
332,12 → 383,12
mutex_lock(&TASK->udebug.lock);
mutex_lock(&THREAD->udebug.lock);
 
printf("udebug_thread_b_event\n");
printf("- check state\n");
LOG("udebug_thread_b_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",
LOG("- debug_active: %s, udebug.stop: %s\n",
THREAD->udebug.debug_active ? "yes(+)" : "no(-)",
THREAD->udebug.stop ? "yes(-)" : "no(+)");
mutex_unlock(&THREAD->udebug.lock);
345,7 → 396,7
return;
}
 
printf("- trigger event\n");
LOG("- trigger event\n");
 
call = THREAD->udebug.go_call;
THREAD->udebug.go_call = NULL;
366,12 → 417,17
mutex_unlock(&THREAD->udebug.lock);
mutex_unlock(&TASK->udebug.lock);
 
printf("- sleep\n");
LOG("- sleep\n");
udebug_wait_for_go(&THREAD->udebug.go_wq);
 
udebug_int_unlock();
}
 
/** Thread-termination event hook.
*
* Must be called when the current thread is terminating.
* Generates a THREAD_E event.
*/
void udebug_thread_e_event(void)
{
call_t *call;
381,8 → 437,8
mutex_lock(&TASK->udebug.lock);
mutex_lock(&THREAD->udebug.lock);
 
// printf("udebug_thread_e_event\n");
// printf("- check state\n");
LOG("udebug_thread_e_event\n");
LOG("- check state\n");
 
/* Must only generate events when in debugging session */
if (THREAD->udebug.debug_active != true) {
394,7 → 450,7
return;
}
 
// printf("- trigger event\n");
LOG("- trigger event\n");
 
call = THREAD->udebug.go_call;
THREAD->udebug.go_call = NULL;
481,8 → 537,12
/**
* Terminate task debugging session.
*
* \param ta->udebug.lock must be already locked.
* \return Zero on success or negative error code.
* Gracefully terminates the debugging session for a task. If the debugger
* is still waiting for events on some threads, it will receive a
* FINISHED event for each of them.
*
* @param ta Task structure. ta->udebug.lock must be already locked.
* @return Zero on success or negative error code.
*/
int udebug_task_cleanup(struct task *ta)
{
491,14 → 551,14
int flags;
ipl_t ipl;
 
printf("udebug_task_cleanup()\n");
printf("task %llu\n", ta->taskid);
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) {
printf("udebug_task_cleanup(): task not being debugged\n");
LOG("udebug_task_cleanup(): task not being debugged\n");
return EINVAL;
}
 
531,9 → 591,10
t->udebug.stop = true;
 
/* Answer GO call */
printf("answer GO call with EVENT_FINISHED\n");
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_SET_ARG1(t->udebug.go_call->data,
UDEBUG_EVENT_FINISHED);
 
ipc_answer(&ta->answerbox, t->udebug.go_call);
t->udebug.go_call = NULL;
/branches/tracing/kernel/generic/src/udebug/udebug_ops.c
33,9 → 33,13
/**
* @file
* @brief Udebug operations.
*
* Udebug operations on tasks and threads are implemented here. The
* functions defined here are called from the udebug_ipc module
* when servicing udebug IPC messages.
*/
#include <print.h>
#include <debug.h>
#include <proc/task.h>
#include <proc/thread.h>
#include <arch.h>
65,6 → 69,9
* thread from leaving the debugging session, while relaxing from
* the t->lock spinlock to the t->udebug.lock mutex.
*
* @param t Pointer, need not at all be valid.
* @param having_go Required thread state.
*
* Returns EOK if all went well, or an error code otherwise.
*/
static int _thread_op_begin(thread_t *t, bool having_go)
146,14 → 153,25
return EOK; /* All went well */
}
 
 
/** End debugging operation on a thread. */
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.
/** Begin debugging the current task.
*
* Initiates a debugging session for the current task (and its threads).
* When the debugging session has started a reply will be sent to the
* UDEBUG_BEGIN call. This may happen immediately in this function if
* all the threads in this task are stoppable at the moment and in this
* case the function returns 1.
*
* Otherwise the function returns 0 and the reply will be sent as soon as
* all the threads become stoppable (i.e. they can be considered stopped).
*
* @param call The BEGIN call we are servicing.
* @return 0 (OK, but not done yet), 1 (done) or negative error code.
*/
int udebug_begin(call_t *call)
{
162,14 → 180,14
thread_t *t;
link_t *cur;
 
printf("udebug_begin()\n");
LOG("udebug_begin()\n");
 
mutex_lock(&TASK->udebug.lock);
printf("debugging task %llu\n", TASK->taskid);
LOG("debugging task %llu\n", TASK->taskid);
 
if (TASK->udebug.dt_state != UDEBUG_TS_INACTIVE) {
mutex_unlock(&TASK->udebug.lock);
printf("udebug_begin(): busy error\n");
LOG("udebug_begin(): busy error\n");
 
return EBUSY;
}
199,20 → 217,25
 
mutex_unlock(&TASK->udebug.lock);
 
printf("udebug_begin() done (%s)\n",
LOG("udebug_begin() done (%s)\n",
reply ? "reply" : "stoppability wait");
 
return reply;
}
 
/** Finish debugging the current task.
*
* Closes the debugging session for the current task.
* @return Zero on success or negative error code.
*/
int udebug_end(void)
{
int rc;
 
printf("udebug_end()\n");
LOG("udebug_end()\n");
 
mutex_lock(&TASK->udebug.lock);
printf("task %llu\n", TASK->taskid);
LOG("task %" PRIu64 "\n", TASK->taskid);
 
rc = udebug_task_cleanup(TASK);
 
221,17 → 244,22
return rc;
}
 
/** Set the event mask.
*
* Sets the event mask that determines which events are enabled.
*
* @param mask Or combination of events that should be enabled.
* @return Zero on success or negative error code.
*/
int udebug_set_evmask(udebug_evmask_t mask)
{
printf("udebug_set_mask()\n");
LOG("udebug_set_mask()\n");
 
printf("debugging task %llu\n", TASK->taskid);
 
mutex_lock(&TASK->udebug.lock);
 
if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
mutex_unlock(&TASK->udebug.lock);
printf("udebug_set_mask(): not active debuging session\n");
LOG("udebug_set_mask(): not active debuging session\n");
 
return EINVAL;
}
243,13 → 271,19
return 0;
}
 
 
/** Give thread GO.
*
* Upon recieving a go message, the thread is given GO. Having GO
* means the thread is allowed to execute userspace code (until
* a debugging event or STOP occurs, at which point the thread loses GO.
*
* @param t The thread to operate on (unlocked and need not be valid).
* @param call The GO call that we are servicing.
*/
int udebug_go(thread_t *t, call_t *call)
{
int rc;
 
// printf("udebug_go()\n");
 
/* On success, this will lock t->udebug.lock */
rc = _thread_op_begin(t, false);
if (rc != EOK) {
270,11 → 304,19
return 0;
}
 
/** Stop a thread (i.e. take its GO away)
*
* Generates a STOP event as soon as the thread becomes stoppable (i.e.
* can be considered stopped).
*
* @param t The thread to operate on (unlocked and need not be valid).
* @param call The GO call that we are servicing.
*/
int udebug_stop(thread_t *t, call_t *call)
{
int rc;
 
printf("udebug_stop()\n");
LOG("udebug_stop()\n");
mutex_lock(&TASK->udebug.lock);
 
/*
298,7 → 340,7
/*
* Answer GO call
*/
printf("udebug_stop - answering go call\n");
LOG("udebug_stop - answering go call\n");
 
/* Make sure nobody takes this call away from us */
call = t->udebug.go_call;
306,7 → 348,7
 
IPC_SET_RETVAL(call->data, 0);
IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP);
printf("udebug_stop/ipc_answer\n");
LOG("udebug_stop/ipc_answer\n");
 
THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
 
315,10 → 357,29
ipc_answer(&TASK->answerbox, call);
mutex_unlock(&TASK->udebug.lock);
 
printf("udebog_stop/done\n");
LOG("udebog_stop/done\n");
return 0;
}
 
/** Read the list of userspace threads in the current task.
*
* The list takes the form of a sequence of thread hashes (i.e. the pointers
* to thread structures). A buffer of size @a buf_size is allocated and
* a pointer to it written to @a buffer. The sequence of hashes is written
* into this buffer.
*
* If the sequence is longer than @a buf_size bytes, only as much hashes
* as can fit are copied. The number of thread hashes copied is stored
* in @a n.
*
* The rationale for having @a buf_size is that this function is only
* used for servicing the THREAD_READ message, which always specifies
* a maximum size for the userspace buffer.
*
* @param buffer The buffer for storing thread hashes.
* @param buf_size Buffer size in bytes.
* @param n The actual number of hashes copied will be stored here.
*/
int udebug_thread_read(void **buffer, size_t buf_size, size_t *n)
{
thread_t *t;
330,7 → 391,7
int flags;
size_t max_ids;
 
printf("udebug_thread_read()\n");
LOG("udebug_thread_read()\n");
 
/* Allocate a buffer to hold thread IDs */
id_buffer = malloc(buf_size, 0);
380,13 → 441,23
return 0;
}
 
/** Read the arguments of a system call.
*
* The arguments of the system call being being executed are copied
* to an allocated buffer and a pointer to it is written to @a buffer.
* The size of the buffer is exactly such that it can hold the maximum number
* of system-call arguments.
*
* Unless the thread is currently blocked in a SYSCALL_B or SYSCALL_E event,
* this function will fail with an EINVAL error code.
*
* @param buffer The buffer for storing thread hashes.
*/
int udebug_args_read(thread_t *t, void **buffer)
{
int rc;
unative_t *arg_buffer;
 
// printf("udebug_args_read()\n");
 
/* Prepare a buffer to hold the arguments */
arg_buffer = malloc(6 * sizeof(unative_t), 0);
 
470,7 → 541,16
return 0;
}
 
 
/** Read the memory of the debugged task.
*
* Reads @a n bytes from the address space of the debugged task, starting
* from @a uspace_addr. The bytes are copied into an allocated buffer
* and a pointer to it is written into @a buffer.
*
* @param uspace_addr Address from where to start reading.
* @param n Number of bytes to read.
* @param buffer For storing a pointer to the allocated buffer.
*/
int udebug_mem_read(unative_t uspace_addr, size_t n, void **buffer)
{
void *data_buffer;
486,8 → 566,6
 
data_buffer = malloc(n, 0);
 
// printf("udebug_mem_read: src=%u, size=%u\n", uspace_addr, n);
 
/* 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);
/branches/tracing/kernel/Makefile
292,7 → 292,7
 
ifeq ($(CONFIG_UDEBUG),y)
GENERIC_SOURCES += \
generic/src/ipc/ipc_kbox.c \
generic/src/ipc/kbox.c \
generic/src/udebug/udebug.c \
generic/src/udebug/udebug_ops.c \
generic/src/udebug/udebug_ipc.c
/branches/tracing/kernel/arch/sparc64/include/trap/syscall.h
31,26 → 31,14
*/
/**
* @file
* @brief This file contains the trap_instruction handler.
*
* The trap_instruction trap is used to implement syscalls.
* @brief
*/
 
#ifndef KERN_sparc64_SYSCALL_TRAP_H_
#define KERN_sparc64_SYSCALL_TRAP_H_
 
#define TT_TRAP_INSTRUCTION(n) (0x100 + (n))
#define TT_TRAP_INSTRUCTION_LAST TT_TRAP_INSTRUCTION(127)
#define TT_TRAP_INSTRUCTION_0 0x100
 
#ifdef __ASM__
 
.macro TRAP_INSTRUCTION n
ba trap_instruction_handler
mov TT_TRAP_INSTRUCTION(\n) - TT_TRAP_INSTRUCTION(0), %g2
.endm
 
#endif /* __ASM__ */
 
#endif
 
/** @}
/branches/tracing/kernel/arch/sparc64/src/trap/trap_table.S
329,198 → 329,22
fill_1_normal_tl0:
FILL_NORMAL_HANDLER_USERSPACE
 
/* TT = 0x100, TL = 0, trap_instruction_0 */
.org trap_table + TT_TRAP_INSTRUCTION(0)*ENTRY_SIZE
.global trap_instruction_0_tl0
trap_instruction_0_tl0:
TRAP_INSTRUCTION 0
/* TT = 0x100 - 0x17f, TL = 0, trap_instruction_0 - trap_instruction_7f */
.irp cur, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,\
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,\
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,\
58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,\
77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,\
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,\
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,\
127
.org trap_table + (TT_TRAP_INSTRUCTION_0+\cur)*ENTRY_SIZE
.global trap_instruction_\cur\()_tl0
trap_instruction_\cur\()_tl0:
ba trap_instruction_handler
mov \cur, %g2
.endr
 
/* TT = 0x101, TL = 0, trap_instruction_1 */
.org trap_table + TT_TRAP_INSTRUCTION(1)*ENTRY_SIZE
.global trap_instruction_1_tl0
trap_instruction_1_tl0:
TRAP_INSTRUCTION 1
 
/* TT = 0x102, TL = 0, trap_instruction_2 */
.org trap_table + TT_TRAP_INSTRUCTION(2)*ENTRY_SIZE
.global trap_instruction_2_tl0
trap_instruction_2_tl0:
TRAP_INSTRUCTION 2
 
/* TT = 0x103, TL = 0, trap_instruction_3 */
.org trap_table + TT_TRAP_INSTRUCTION(3)*ENTRY_SIZE
.global trap_instruction_3_tl0
trap_instruction_3_tl0:
TRAP_INSTRUCTION 3
 
/* TT = 0x104, TL = 0, trap_instruction_4 */
.org trap_table + TT_TRAP_INSTRUCTION(4)*ENTRY_SIZE
.global trap_instruction_4_tl0
trap_instruction_4_tl0:
TRAP_INSTRUCTION 4
 
/* TT = 0x105, TL = 0, trap_instruction_5 */
.org trap_table + TT_TRAP_INSTRUCTION(5)*ENTRY_SIZE
.global trap_instruction_5_tl0
trap_instruction_5_tl0:
TRAP_INSTRUCTION 5
 
/* TT = 0x106, TL = 0, trap_instruction_6 */
.org trap_table + TT_TRAP_INSTRUCTION(6)*ENTRY_SIZE
.global trap_instruction_6_tl0
trap_instruction_6_tl0:
TRAP_INSTRUCTION 6
 
/* TT = 0x107, TL = 0, trap_instruction_7 */
.org trap_table + TT_TRAP_INSTRUCTION(7)*ENTRY_SIZE
.global trap_instruction_7_tl0
trap_instruction_7_tl0:
TRAP_INSTRUCTION 7
 
/* TT = 0x108, TL = 0, trap_instruction_8 */
.org trap_table + TT_TRAP_INSTRUCTION(8)*ENTRY_SIZE
.global trap_instruction_8_tl0
trap_instruction_8_tl0:
TRAP_INSTRUCTION 8
 
/* TT = 0x109, TL = 0, trap_instruction_9 */
.org trap_table + TT_TRAP_INSTRUCTION(9)*ENTRY_SIZE
.global trap_instruction_9_tl0
trap_instruction_9_tl0:
TRAP_INSTRUCTION 9
 
/* TT = 0x10a, TL = 0, trap_instruction_10 */
.org trap_table + TT_TRAP_INSTRUCTION(10)*ENTRY_SIZE
.global trap_instruction_10_tl0
trap_instruction_10_tl0:
TRAP_INSTRUCTION 10
 
/* TT = 0x10b, TL = 0, trap_instruction_11 */
.org trap_table + TT_TRAP_INSTRUCTION(11)*ENTRY_SIZE
.global trap_instruction_11_tl0
trap_instruction_11_tl0:
TRAP_INSTRUCTION 11
 
/* TT = 0x10c, TL = 0, trap_instruction_12 */
.org trap_table + TT_TRAP_INSTRUCTION(12)*ENTRY_SIZE
.global trap_instruction_12_tl0
trap_instruction_12_tl0:
TRAP_INSTRUCTION 12
 
/* TT = 0x10d, TL = 0, trap_instruction_13 */
.org trap_table + TT_TRAP_INSTRUCTION(13)*ENTRY_SIZE
.global trap_instruction_13_tl0
trap_instruction_13_tl0:
TRAP_INSTRUCTION 13
 
/* TT = 0x10e, TL = 0, trap_instruction_14 */
.org trap_table + TT_TRAP_INSTRUCTION(14)*ENTRY_SIZE
.global trap_instruction_14_tl0
trap_instruction_14_tl0:
TRAP_INSTRUCTION 14
 
/* TT = 0x10f, TL = 0, trap_instruction_15 */
.org trap_table + TT_TRAP_INSTRUCTION(15)*ENTRY_SIZE
.global trap_instruction_15_tl0
trap_instruction_15_tl0:
TRAP_INSTRUCTION 15
 
/* TT = 0x110, TL = 0, trap_instruction_16 */
.org trap_table + TT_TRAP_INSTRUCTION(16)*ENTRY_SIZE
.global trap_instruction_16_tl0
trap_instruction_16_tl0:
TRAP_INSTRUCTION 16
 
/* TT = 0x111, TL = 0, trap_instruction_17 */
.org trap_table + TT_TRAP_INSTRUCTION(17)*ENTRY_SIZE
.global trap_instruction_17_tl0
trap_instruction_17_tl0:
TRAP_INSTRUCTION 17
 
/* TT = 0x112, TL = 0, trap_instruction_18 */
.org trap_table + TT_TRAP_INSTRUCTION(18)*ENTRY_SIZE
.global trap_instruction_18_tl0
trap_instruction_18_tl0:
TRAP_INSTRUCTION 18
 
/* TT = 0x113, TL = 0, trap_instruction_19 */
.org trap_table + TT_TRAP_INSTRUCTION(19)*ENTRY_SIZE
.global trap_instruction_19_tl0
trap_instruction_19_tl0:
TRAP_INSTRUCTION 19
 
/* TT = 0x114, TL = 0, trap_instruction_20 */
.org trap_table + TT_TRAP_INSTRUCTION(20)*ENTRY_SIZE
.global trap_instruction_20_tl0
trap_instruction_20_tl0:
TRAP_INSTRUCTION 20
 
/* TT = 0x115, TL = 0, trap_instruction_21 */
.org trap_table + TT_TRAP_INSTRUCTION(21)*ENTRY_SIZE
.global trap_instruction_21_tl0
trap_instruction_21_tl0:
TRAP_INSTRUCTION 21
 
/* TT = 0x116, TL = 0, trap_instruction_22 */
.org trap_table + TT_TRAP_INSTRUCTION(22)*ENTRY_SIZE
.global trap_instruction_22_tl0
trap_instruction_22_tl0:
TRAP_INSTRUCTION 22
 
/* TT = 0x117, TL = 0, trap_instruction_23 */
.org trap_table + TT_TRAP_INSTRUCTION(23)*ENTRY_SIZE
.global trap_instruction_23_tl0
trap_instruction_23_tl0:
TRAP_INSTRUCTION 23
 
/* TT = 0x118, TL = 0, trap_instruction_24 */
.org trap_table + TT_TRAP_INSTRUCTION(24)*ENTRY_SIZE
.global trap_instruction_24_tl0
trap_instruction_24_tl0:
TRAP_INSTRUCTION 24
 
/* TT = 0x119, TL = 0, trap_instruction_25 */
.org trap_table + TT_TRAP_INSTRUCTION(25)*ENTRY_SIZE
.global trap_instruction_25_tl0
trap_instruction_25_tl0:
TRAP_INSTRUCTION 25
 
/* TT = 0x11a, TL = 0, trap_instruction_26 */
.org trap_table + TT_TRAP_INSTRUCTION(26)*ENTRY_SIZE
.global trap_instruction_26_tl0
trap_instruction_26_tl0:
TRAP_INSTRUCTION 26
 
/* TT = 0x11b, TL = 0, trap_instruction_27 */
.org trap_table + TT_TRAP_INSTRUCTION(27)*ENTRY_SIZE
.global trap_instruction_27_tl0
trap_instruction_27_tl0:
TRAP_INSTRUCTION 27
 
/* TT = 0x11c, TL = 0, trap_instruction_28 */
.org trap_table + TT_TRAP_INSTRUCTION(28)*ENTRY_SIZE
.global trap_instruction_28_tl0
trap_instruction_28_tl0:
TRAP_INSTRUCTION 28
 
/* TT = 0x11d, TL = 0, trap_instruction_29 */
.org trap_table + TT_TRAP_INSTRUCTION(29)*ENTRY_SIZE
.global trap_instruction_29_tl0
trap_instruction_29_tl0:
TRAP_INSTRUCTION 29
 
/* TT = 0x11e, TL = 0, trap_instruction_30 */
.org trap_table + TT_TRAP_INSTRUCTION(30)*ENTRY_SIZE
.global trap_instruction_30_tl0
trap_instruction_30_tl0:
TRAP_INSTRUCTION 30
 
/* TT = 0x11f, TL = 0, trap_instruction_31 */
.org trap_table + TT_TRAP_INSTRUCTION(31)*ENTRY_SIZE
.global trap_instruction_31_tl0
trap_instruction_31_tl0:
TRAP_INSTRUCTION 31
 
/*
* Handlers for TL>0.
*/
/branches/tracing/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/tracing/uspace/app/bdsh/exec.c
46,13 → 46,13
#include "errors.h"
 
/* FIXME: Just have find_command() return an allocated string */
char *found;
static char *found;
 
static char *find_command(char *);
static unsigned int try_access(const char *);
static int try_access(const char *);
 
/* work-around for access() */
static unsigned int try_access(const char *f)
static int try_access(const char *f)
{
int fd;
 
/branches/tracing/uspace/app/trace/trace.c
41,6 → 41,8
#include <errno.h>
#include <udebug.h>
#include <async.h>
#include <task.h>
#include <loader/loader.h>
 
// Temporary: service and method names
#include "proto.h"
51,10 → 53,11
#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;
uintptr_t thread_hash_buf[THBUF_SIZE];
int n_threads;
 
int next_thread_id;
 
61,32 → 64,88
int phoneid;
int abort_trace;
 
unsigned thash;
uintptr_t thash;
volatile int paused;
 
void thread_trace_start(unsigned thread_hash);
void thread_trace_start(uintptr_t thread_hash);
 
static proto_t *proto_console;
static task_id_t task_id;
static loader_t *task_ldr;
 
static int task_connect(task_id_t task_id)
/** Combination of events/data to print. */
display_mask_t display_mask;
 
static int program_run_fibril(void *arg);
 
static void program_run(void)
{
fid_t fid;
 
fid = fibril_create(program_run_fibril, NULL);
if (fid == 0) {
printf("Error creating fibril\n");
exit(1);
}
 
fibril_add_ready(fid);
}
 
static int program_run_fibril(void *arg)
{
int rc;
 
printf("ipc_connect_task(%lld)... ", task_id);
/*
* This must be done in background as it will block until
* we let the task reply to this call.
*/
rc = loader_run(task_ldr);
if (rc != 0) {
printf("Error running program\n");
exit(1);
}
 
free(task_ldr);
task_ldr = NULL;
 
printf("program_run_fibril exiting\n");
return 0;
}
 
 
static int connect_task(task_id_t task_id)
{
int rc;
 
rc = ipc_connect_kbox(task_id);
printf("-> %d\n", rc);
 
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;
if (rc < 0) return rc;
 
printf("udebug_begin()... ");
rc = udebug_begin(phoneid);
printf("-> %d\n", rc);
if (rc < 0) return rc;
if (rc < 0) {
printf("udebug_begin() -> %d\n", rc);
return rc;
}
 
printf("udebug_set_evmask(0x%x)... ", UDEBUG_EM_ALL);
rc = udebug_set_evmask(phoneid, UDEBUG_EM_ALL);
printf("-> %d\n", rc);
if (rc < 0) return rc;
if (rc < 0) {
printf("udebug_set_evmask(0x%x) -> %d\n ", UDEBUG_EM_ALL, rc);
return rc;
}
 
return 0;
}
98,66 → 157,101
size_t tb_needed;
int i;
 
printf("send IPC_M_DEBUG_THREAD_READ message\n");
rc = udebug_thread_read(phoneid, thread_hash_buf,
THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed);
printf("-> %d\n", rc);
if (rc < 0) return rc;
if (rc < 0) {
printf("udebug_thread_read() -> %d\n", rc);
return rc;
}
 
n_threads = tb_copied / sizeof(unsigned);
n_threads = tb_copied / sizeof(uintptr_t);
 
printf("thread IDs:");
for (i=0; i<n_threads; i++) {
printf(" %u", thread_hash_buf[i]);
printf("Threads:");
for (i = 0; i < n_threads; i++) {
printf(" [%d] (hash 0x%lx)", 1+i, thread_hash_buf[i]);
}
printf("\ntotal of %u threads\n", tb_needed/sizeof(unsigned));
printf("\ntotal of %u threads\n", tb_needed / sizeof(uintptr_t));
 
return 0;
}
 
static void print_sc_retval(int retval, rv_type_t rv_type)
void val_print(sysarg_t val, val_type_t v_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);
switch (v_type) {
case V_VOID:
printf("<void>");
break;
 
case V_INTEGER:
printf("%ld", val);
break;
 
case V_HASH:
case V_PTR:
printf("0x%08lx", val);
break;
 
case V_ERRNO:
if (val >= -15 && val <= 0) {
printf("%ld %s (%s)", val,
err_desc[-val].name,
err_desc[-val].desc);
} else {
printf("%d", retval);
printf("%ld", val);
}
} 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);
break;
case V_INT_ERRNO:
if (val >= -15 && val < 0) {
printf("%ld %s (%s)", val,
err_desc[-val].name,
err_desc[-val].desc);
} else {
printf("%d", retval);
printf("%ld", val);
}
break;
 
case V_CHAR:
if (val >= 0x20 && val < 0x7f) {
printf("'%c'", val);
} else {
switch (val) {
case '\a': printf("'\\a'"); break;
case '\b': printf("'\\b'"); break;
case '\n': printf("'\\n'"); break;
case '\r': printf("'\\r'"); break;
case '\t': printf("'\\t'"); break;
case '\\': printf("'\\\\'"); break;
default: printf("'\\x%02lX'", val); break;
}
}
break;
}
}
 
 
static void print_sc_retval(sysarg_t retval, val_type_t val_type)
{
printf(" -> ");
val_print(retval, val_type);
putchar('\n');
}
 
static void print_sc_args(unsigned *sc_args, int n)
static void print_sc_args(sysarg_t *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]);
if (n > 0) printf("%ld", sc_args[0]);
for (i = 1; i < n; i++) {
printf(", %ld", sc_args[i]);
}
putchar(')');
}
 
static void sc_ipc_call_async_fast(unsigned *sc_args, int sc_rc)
static void sc_ipc_call_async_fast(sysarg_t *sc_args, sysarg_t sc_rc)
{
ipc_call_t call;
int phoneid;
ipcarg_t phoneid;
if (sc_rc == IPC_CALLRET_FATAL || sc_rc == IPC_CALLRET_TEMPORARY)
return;
174,7 → 268,7
ipcp_call_out(phoneid, &call, sc_rc);
}
 
static void sc_ipc_call_async_slow(unsigned *sc_args, int sc_rc)
static void sc_ipc_call_async_slow(sysarg_t *sc_args, sysarg_t sc_rc)
{
ipc_call_t call;
int rc;
190,7 → 284,7
}
}
 
static void sc_ipc_call_sync_fast(unsigned *sc_args)
static void sc_ipc_call_sync_fast(sysarg_t *sc_args)
{
ipc_call_t question, reply;
int rc;
218,7 → 312,7
ipcp_call_sync(phoneidx, &question, &reply);
}
 
static void sc_ipc_call_sync_slow(unsigned *sc_args)
static void sc_ipc_call_sync_slow(sysarg_t *sc_args)
{
ipc_call_t question, reply;
int rc;
236,7 → 330,7
ipcp_call_sync(sc_args[0], &question, &reply);
}
 
static void sc_ipc_wait(unsigned *sc_args, int sc_rc)
static void sc_ipc_wait(sysarg_t *sc_args, int sc_rc)
{
ipc_call_t call;
int rc;
253,9 → 347,10
}
}
 
static void event_syscall_b(unsigned thread_id, unsigned thread_hash, unsigned sc_id, int sc_rc)
static void event_syscall_b(unsigned thread_id, uintptr_t thread_hash,
unsigned sc_id, sysarg_t sc_rc)
{
unsigned sc_args[6];
sysarg_t sc_args[6];
int rc;
 
/* Read syscall arguments */
271,16 → 366,19
return;
}
 
/* Print syscall name, id and arguments */
printf("%s", syscall_desc[sc_id].name);
print_sc_args(sc_args, syscall_desc[sc_id].n_args);
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)
static void event_syscall_e(unsigned thread_id, uintptr_t thread_hash,
unsigned sc_id, sysarg_t sc_rc)
{
unsigned sc_args[6];
sysarg_t sc_args[6];
int rv_type;
int rc;
 
297,8 → 395,11
return;
}
 
rv_type = syscall_desc[sc_id].rv_type;
print_sc_retval(sc_rc, rv_type);
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:
323,10 → 424,10
async_serialize_end();
}
 
static void event_thread_b(unsigned hash)
static void event_thread_b(uintptr_t hash)
{
async_serialize_start();
printf("new thread, hash 0x%x\n", hash);
printf("New thread, hash 0x%lx\n", hash);
async_serialize_end();
 
thread_trace_start(hash);
336,14 → 437,14
{
int rc;
unsigned ev_type;
unsigned thread_hash;
uintptr_t thread_hash;
unsigned thread_id;
unsigned val0, val1;
sysarg_t val0, val1;
 
thread_hash = (unsigned)thread_hash_arg;
thread_hash = (uintptr_t)thread_hash_arg;
thread_id = next_thread_id++;
 
printf("trace_loop(%d)\n", thread_id);
printf("Start tracing thread [%d] (hash 0x%lx)\n", thread_id, thread_hash);
 
while (!abort_trace) {
 
353,7 → 454,7
 
// printf("rc = %d, ev_type=%d\n", rc, ev_type);
if (ev_type == UDEBUG_EVENT_FINISHED) {
printf("thread %u debugging finished\n", thread_id);
/* Done tracing this thread */
break;
}
 
366,24 → 467,24
event_syscall_e(thread_id, thread_hash, val0, (int)val1);
break;
case UDEBUG_EVENT_STOP:
printf("stop event\n");
printf("waiting for resume\n");
printf("Stop event\n");
printf("Waiting for resume\n");
while (paused) {
usleep(1000000);
fibril_yield();
printf(".");
}
printf("resumed\n");
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);
printf("Thread 0x%lx exited\n", val0);
abort_trace = 1;
break;
default:
printf("unknown event type %d\n", ev_type);
printf("Unknown event type %d\n", ev_type);
break;
}
}
390,11 → 491,11
 
}
 
printf("trace_loop(%d) exiting\n", thread_id);
printf("Finished tracing thread [%d]\n", thread_id);
return 0;
}
 
void thread_trace_start(unsigned thread_hash)
void thread_trace_start(uintptr_t thread_hash)
{
fid_t fid;
 
407,25 → 508,61
fibril_add_ready(fid);
}
 
static void trace_active_task(task_id_t task_id)
static loader_t *preload_task(const char *path, char *const argv[],
task_id_t *task_id)
{
int i;
loader_t *ldr;
int rc;
int c;
 
printf("Syscall Tracer\n");
/* Spawn a program loader */
ldr = loader_spawn();
if (ldr == NULL)
return 0;
 
rc = task_connect(task_id);
if (rc < 0) {
printf("Failed to connect to task %lld\n", task_id);
return;
}
/* Get task ID. */
rc = loader_get_task_id(ldr, task_id);
if (rc != EOK)
goto error;
 
printf("Connected to task %lld\n", task_id);
/* Send program pathname */
rc = loader_set_pathname(ldr, path);
if (rc != EOK)
goto error;
 
/* Send arguments */
rc = loader_set_args(ldr, argv);
if (rc != EOK)
goto error;
 
/* Load the program. */
rc = loader_load_program(ldr);
if (rc != EOK)
goto error;
 
/* Success */
return ldr;
 
/* Error exit */
error:
loader_abort(ldr);
free(ldr);
return NULL;
}
 
static void trace_task(task_id_t task_id)
{
int i;
int rc;
int c;
 
ipcp_init();
ipcp_connection_set(1, 0, proto_console);
 
/*
* 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);
451,7 → 588,7
}
}
 
printf("terminate debugging session...\n");
printf("\nTerminate debugging session...\n");
abort_trace = 1;
udebug_end(phoneid);
ipc_hangup(phoneid);
458,7 → 595,7
 
ipcp_cleanup();
 
printf("done\n");
printf("Done\n");
return;
}
 
467,6 → 604,22
proto_t *p;
oper_t *o;
 
val_type_t arg_def[OPER_MAX_ARGS] = {
V_INTEGER,
V_INTEGER,
V_INTEGER,
V_INTEGER,
V_INTEGER
};
 
val_type_t resp_def[OPER_MAX_ARGS] = {
V_INTEGER,
V_INTEGER,
V_INTEGER,
V_INTEGER,
V_INTEGER
};
 
next_thread_id = 1;
paused = 0;
 
473,38 → 626,45
proto_init();
 
p = proto_new("vfs");
o = oper_new("read");
o = oper_new("read", 1, arg_def, V_ERRNO, 1, resp_def);
proto_add_oper(p, VFS_READ, o);
o = oper_new("write");
o = oper_new("write", 1, arg_def, V_ERRNO, 1, resp_def);
proto_add_oper(p, VFS_WRITE, o);
o = oper_new("truncate");
o = oper_new("truncate", 5, arg_def, V_ERRNO, 0, resp_def);
proto_add_oper(p, VFS_TRUNCATE, o);
o = oper_new("mount");
o = oper_new("mount", 2, arg_def, V_ERRNO, 0, resp_def);
proto_add_oper(p, VFS_MOUNT, o);
o = oper_new("unmount");
proto_add_oper(p, VFS_UNMOUNT, o);
/* o = oper_new("unmount", 0, arg_def);
proto_add_oper(p, VFS_UNMOUNT, o);*/
 
proto_register(SERVICE_VFS, p);
 
p = proto_new("console");
o = oper_new("getchar");
resp_def[0] = V_CHAR;
o = oper_new("getchar", 0, arg_def, V_INTEGER, 2, resp_def);
proto_add_oper(p, CONSOLE_GETCHAR, o);
o = oper_new("putchar");
 
arg_def[0] = V_CHAR;
o = oper_new("putchar", 1, arg_def, V_VOID, 0, resp_def);
proto_add_oper(p, CONSOLE_PUTCHAR, o);
o = oper_new("clear");
o = oper_new("clear", 0, arg_def, V_VOID, 0, resp_def);
proto_add_oper(p, CONSOLE_CLEAR, o);
o = oper_new("goto");
 
arg_def[0] = V_INTEGER; arg_def[1] = V_INTEGER;
o = oper_new("goto", 2, arg_def, V_VOID, 0, resp_def);
proto_add_oper(p, CONSOLE_GOTO, o);
o = oper_new("getsize");
 
resp_def[0] = V_INTEGER; resp_def[1] = V_INTEGER;
o = oper_new("getsize", 0, arg_def, V_INTEGER, 2, resp_def);
proto_add_oper(p, CONSOLE_GETSIZE, o);
o = oper_new("flush");
o = oper_new("flush", 0, arg_def, V_VOID, 0, resp_def);
proto_add_oper(p, CONSOLE_FLUSH, o);
o = oper_new("set_style");
 
arg_def[0] = V_INTEGER; arg_def[1] = V_INTEGER;
o = oper_new("set_style", 2, arg_def, V_INTEGER, 0, resp_def);
proto_add_oper(p, CONSOLE_SET_STYLE, o);
o = oper_new("cursor_visibility");
o = oper_new("cursor_visibility", 1, arg_def, V_VOID, 0, resp_def);
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);
512,30 → 672,133
 
static void print_syntax()
{
printf("syntax: trace <task_id>\n");
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");
}
 
int main(int argc, char *argv[])
static display_mask_t parse_display_mask(char *text)
{
task_id_t task_id;
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;
 
if (argc != 2) {
printf("Mising argument\n");
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);
task_ldr = NULL;
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 0;
printf("Extra arguments\n");
print_syntax();
return 1;
return -1;
}
 
task_id = strtol(argv[1], &err_p, 10);
if (argc < 1) {
printf("Missing argument\n");
print_syntax();
return -1;
}
 
if (*err_p) {
printf("Task ID syntax error\n");
print_syntax();
/* Preload the specified program file. */
printf("Spawning '%s' with arguments:\n", *argv);
{
char **cp = argv;
while (*cp) printf("'%s'\n", *cp++);
}
task_ldr = preload_task(*argv, argv, &task_id);
 
return 0;
}
 
int main(int argc, char *argv[])
{
int rc;
 
printf("System Call / IPC Tracer\n");
 
display_mask = DM_THREAD | DM_SYSTEM | DM_USER;
 
if (parse_args(argc, argv) < 0)
return 1;
 
main_init();
 
rc = connect_task(task_id);
if (rc < 0) {
printf("Failed connecting to task %lld\n", task_id);
return 1;
}
 
main_init();
trace_active_task(task_id);
printf("Connected to task %lld\n", task_id);
 
if (task_ldr != NULL) {
program_run();
}
 
trace_task(task_id);
 
return 0;
}
 
/** @}
/branches/tracing/uspace/app/trace/syscalls.h
35,17 → 35,12
#ifndef SYSCALLS_H_
#define SYSCALLS_H_
 
typedef enum {
RV_INTEGER,
RV_HASH,
RV_ERRNO,
RV_INT_ERRNO
} rv_type_t;
#include "trace.h"
 
typedef struct {
char *name;
int n_args;
rv_type_t rv_type;
val_type_t rv_type;
} sc_desc_t;
 
extern const sc_desc_t syscall_desc[];
/branches/tracing/uspace/app/trace/proto.c
37,6 → 37,7
#include <ipc/ipc.h>
#include <libadt/hash_table.h>
 
#include "trace.h"
#include "proto.h"
 
#define SRV_PROTO_TABLE_CHAINS 32
172,6 → 173,11
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;
204,13 → 210,25
oper->name = name;
}
 
oper_t *oper_new(char *name)
oper_t *oper_new(char *name, int argc, val_type_t *arg_types,
val_type_t rv_type, int respc, val_type_t *resp_types)
{
oper_t *o;
int i;
 
o = malloc(sizeof(oper_t));
oper_struct_init(o, name);
 
o->argc = argc;
for (i = 0; i < argc; i++)
o->arg_type[i] = arg_types[i];
 
o->rv_type = rv_type;
 
o->respc = respc;
for (i = 0; i < respc; i++)
o->resp_type[i] = resp_types[i];
 
return o;
}
 
/branches/tracing/uspace/app/trace/trace.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 TRACE_H_
#define TRACE_H_
 
#include <sys/types.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;
 
typedef enum {
V_VOID,
V_INTEGER,
V_PTR,
V_HASH,
V_ERRNO,
V_INT_ERRNO,
V_CHAR
} val_type_t;
 
/** Combination of events to print. */
extern display_mask_t display_mask;
 
void val_print(sysarg_t val, val_type_t v_type);
 
#endif
 
/** @}
*/
/branches/tracing/uspace/app/trace/proto.h
36,9 → 36,21
#define PROTO_H_
 
#include <libadt/hash_table.h>
#include <ipc/ipc.h>
#include "trace.h"
 
#define OPER_MAX_ARGS (IPC_CALL_LEN - 1)
 
typedef struct {
char *name;
 
int argc;
val_type_t arg_type[OPER_MAX_ARGS];
 
val_type_t rv_type;
 
int respc;
val_type_t resp_type[OPER_MAX_ARGS];
} oper_t;
 
typedef struct {
58,12 → 70,15
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);
oper_t *oper_new(char *name, int argc, val_type_t *arg_types,
val_type_t rv_type, int respc, val_type_t *resp_types);
 
 
 
#endif
 
/** @}
/branches/tracing/uspace/app/trace/ipcp.c
38,15 → 38,17
 
#include "ipc_desc.h"
#include "proto.h"
#include "trace.h"
#include "ipcp.h"
 
#define IPCP_CALLID_SYNC 0
 
typedef struct {
int phone_hash;
ipcarg_t phone_hash;
ipc_call_t question;
oper_t *oper;
 
int call_hash;
ipc_callid_t call_hash;
 
link_t link;
} pending_call_t;
63,6 → 65,12
#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);
89,6 → 97,7
// printf("pending_call_compare\n");
hs = hash_table_get_instance(item, pending_call_t, link);
 
// FIXME: this will fail if sizeof(long) < sizeof(void *).
return key[0] == hs->call_hash;
}
 
115,38 → 124,63
 
static void ipc_m_print(proto_t *proto, ipcarg_t method)
{
ipc_m_desc_t *desc;
oper_t *oper;
 
/* FIXME: too slow */
desc = ipc_methods;
while (desc->number != 0) {
if (desc->number == method) {
printf("%s (%d)", desc->name, method);
return;
}
/* Try system methods first */
oper = proto_get_oper(proto_system, method);
 
++desc;
if (oper == NULL && proto != NULL) {
/* Not a system method, try the user protocol. */
oper = proto_get_oper(proto, method);
}
 
if (proto != NULL) {
oper = proto_get_oper(proto, method);
if (oper != NULL) {
printf("%s (%d)", oper->name, method);
return;
}
if (oper != NULL) {
printf("%s (%ld)", oper->name, method);
return;
}
 
printf("%d", method);
printf("%ld", method);
}
 
void ipcp_init(void)
{
ipc_m_desc_t *desc;
oper_t *oper;
 
val_type_t arg_def[OPER_MAX_ARGS] = {
V_INTEGER,
V_INTEGER,
V_INTEGER,
V_INTEGER,
V_INTEGER
};
 
/*
* 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, OPER_MAX_ARGS, arg_def, V_INTEGER,
OPER_MAX_ARGS, arg_def);
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);
}
 
155,22 → 189,59
pending_call_t *pcall;
proto_t *proto;
unsigned long key[1];
oper_t *oper;
ipcarg_t *args;
int i;
 
if (have_conn[phone]) proto = connections[phone].proto;
else proto = NULL;
 
// printf("ipcp_call_out()\n");
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)
);
args = call->args;
 
if ((display_mask & DM_IPC) != 0) {
printf("Call ID: 0x%lx, phone: %d, proto: %s, method: ", hash,
phone, (proto ? proto->name : "n/a"));
ipc_m_print(proto, IPC_GET_METHOD(*call));
printf(" args: (%lu, %lu, %lu, %lu, %lu)\n", args[1], args[2],
args[3], args[4], args[5]);
}
 
 
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"));
 
putchar('(');
for (i = 1; i <= oper->argc; ++i) {
if (i > 1) printf(", ");
val_print(args[i], oper->arg_type[i - 1]);
}
putchar(')');
 
if (oper->rv_type == V_VOID && oper->respc == 0) {
/*
* No response data (typically the task will
* not be interested in the response).
* We will not display response.
*/
putchar('.');
}
 
putchar('\n');
}
} else {
oper = NULL;
}
 
/* Store call in hash table for response matching */
 
pcall = malloc(sizeof(pending_call_t));
177,6 → 248,7
pcall->phone_hash = phone;
pcall->question = *call;
pcall->call_hash = hash;
pcall->oper = oper;
 
key[0] = hash;
 
183,33 → 255,71
hash_table_insert(&pending_calls, key, &pcall->link);
}
 
static void parse_answer(pending_call_t *pcall, ipc_call_t *answer)
static void parse_answer(ipc_callid_t hash, pending_call_t *pcall,
ipc_call_t *answer)
{
int phone;
ipcarg_t phone;
ipcarg_t method;
ipcarg_t service;
int retval;
static proto_t proto_unknown = { .name = "unknown" };
ipcarg_t retval;
proto_t *proto;
int cphone;
 
ipcarg_t *resp;
oper_t *oper;
int i;
 
// printf("parse_answer\n");
 
phone = pcall->phone_hash;
method = IPC_GET_METHOD(pcall->question);
retval = IPC_GET_RETVAL(*answer);
printf("phone=%d, method=%d, retval=%d\n",
phone, method, retval);
 
resp = answer->args;
 
if ((display_mask & DM_IPC) != 0) {
printf("Response to 0x%lx: retval=%ld, args = (%lu, %lu, %lu, %lu, %lu)\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) {
oper = pcall->oper;
 
if (oper != NULL && (oper->rv_type != V_VOID || oper->respc > 0)) {
printf("->");
 
if (oper->rv_type != V_VOID) {
putchar(' ');
val_print(retval, oper->rv_type);
}
if (oper->respc > 0) {
putchar(' ');
putchar('(');
for (i = 1; i <= oper->respc; ++i) {
if (i > 1) printf(", ");
val_print(resp[i], oper->resp_type[i - 1]);
}
putchar(')');
}
 
putchar('\n');
}
}
 
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;
if (proto == NULL) proto = proto_unknown;
 
cphone = IPC_GET_ARG5(*answer);
printf("registering connection (phone %d, protocol: %s)\n", cphone,
proto->name);
if ((display_mask & DM_SYSTEM) != 0) {
printf("Registering connection (phone %d, protocol: %s)\n", cphone,
proto->name);
}
ipcp_connection_set(cphone, 0, proto);
}
}
221,19 → 331,12
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 */
printf("Not a response (hash %d)\n", hash);
if ((display_mask & DM_IPC) != 0) {
printf("Not a response (hash 0x%lx)\n", hash);
}
return;
}
 
242,13 → 345,15
 
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);
 
printf("response matched to question\n");
hash_table_remove(&pending_calls, key, 1);
 
parse_answer(pcall, call);
parse_answer(hash, pcall, call);
free(pcall);
}
 
260,8 → 365,10
 
void ipcp_hangup(int phone, int rc)
{
printf("hangup phone %d -> %d\n", phone, rc);
ipcp_connection_clear(phone);
if ((display_mask & DM_SYSTEM) != 0) {
printf("Hang phone %d up -> %d\n", phone, rc);
ipcp_connection_clear(phone);
}
}
 
/** @}
/branches/tracing/uspace/app/trace/syscalls.c
34,45 → 34,46
 
#include <kernel/syscall/syscall.h>
#include "syscalls.h"
#include "trace.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_KLOG] ={ "klog", 3, V_INT_ERRNO },
[SYS_TLS_SET] = { "tls_set", 1, V_ERRNO },
[SYS_THREAD_CREATE] = { "thread_create", 3, V_ERRNO },
[SYS_THREAD_EXIT] = { "thread_exit", 1, V_ERRNO },
[SYS_THREAD_GET_ID] = { "thread_get_id", 1, V_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_TASK_GET_ID] = { "task_get_id", 1, V_ERRNO },
[SYS_FUTEX_SLEEP] = { "futex_sleep_timeout", 3, V_ERRNO },
[SYS_FUTEX_WAKEUP] = { "futex_wakeup", 1, V_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_AS_AREA_CREATE] = { "as_area_create", 3, V_ERRNO },
[SYS_AS_AREA_RESIZE] = { "as_area_resize", 3, V_ERRNO },
[SYS_AS_AREA_DESTROY] = { "as_area_destroy", 1, V_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_CALL_SYNC_FAST] = { "ipc_call_sync_fast", 6, V_ERRNO },
[SYS_IPC_CALL_SYNC_SLOW] = { "ipc_call_sync_slow", 3, V_ERRNO },
[SYS_IPC_CALL_ASYNC_FAST] = { "ipc_call_async_fast", 6, V_HASH },
[SYS_IPC_CALL_ASYNC_SLOW] = { "ipc_call_async_slow", 2, V_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_IPC_ANSWER_FAST] = { "ipc_answer_fast", 6, V_ERRNO },
[SYS_IPC_ANSWER_SLOW] = { "ipc_answer_slow", 2, V_ERRNO },
[SYS_IPC_FORWARD_FAST] = { "ipc_forward_fast", 6, V_ERRNO },
[SYS_IPC_WAIT] = { "ipc_wait_for_call", 3, V_HASH },
[SYS_IPC_HANGUP] = { "ipc_hangup", 1, V_ERRNO },
[SYS_IPC_REGISTER_IRQ] = { "ipc_register_irq", 4, V_ERRNO },
[SYS_IPC_UNREGISTER_IRQ] = { "ipc_unregister_irq", 2, V_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_CAP_GRANT] = { "cap_grant", 2, V_ERRNO },
[SYS_CAP_REVOKE] = { "cap_revoke", 2, V_ERRNO },
[SYS_PHYSMEM_MAP] = { "physmem_map", 4, V_ERRNO },
[SYS_IOSPACE_ENABLE] = { "iospace_enable", 1, V_ERRNO },
[SYS_PREEMPT_CONTROL] = { "preempt_control", 1, V_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 }
[SYS_SYSINFO_VALID] = { "sysinfo_valid", 2, V_HASH },
[SYS_SYSINFO_VALUE] = { "sysinfo_value", 2, V_HASH },
[SYS_DEBUG_ENABLE_CONSOLE] = { "debug_enable_console", 0, V_ERRNO },
[SYS_IPC_CONNECT_KBOX] = { "ipc_connect_kbox", 1, V_ERRNO }
};
 
/** @}
/branches/tracing/uspace/lib/libc/include/task.h
40,7 → 40,7
typedef uint64_t task_id_t;
 
extern task_id_t task_get_id(void);
extern task_id_t task_spawn(const char *path, const char *argv[]);
extern task_id_t task_spawn(const char *path, char *const argv[]);
 
#endif
 
/branches/tracing/uspace/lib/libc/include/loader/pcb.h
40,7 → 40,8
 
typedef void (*entry_point_t)(void);
 
/**
/** Program Control Block.
*
* Holds pointers to data passed from the program loader to the program
* and/or to the dynamic linker. This includes the program entry point,
* arguments, environment variables etc.
/branches/tracing/uspace/lib/libc/include/loader/loader.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 fs
* @{
*/
/** @file
* @brief Program loader interface.
*/
 
#ifndef LIBC_LOADER_H_
#define LIBC_LOADER_H_
 
/** Abstraction of a loader connection */
typedef struct {
/** ID of the phone connected to the loader. */
int phone_id;
} loader_t;
 
extern loader_t *loader_spawn(void);
extern int loader_get_task_id(loader_t *, task_id_t *);
extern int loader_set_pathname(loader_t *, const char *);
extern int loader_set_args(loader_t *, char *const []);
extern int loader_load_program(loader_t *);
extern int loader_run(loader_t *);
extern void loader_abort(loader_t *);
 
#endif
 
/**
* @}
*/
/branches/tracing/uspace/lib/libc/include/ipc/loader.h
32,15 → 32,17
/** @file
*/
 
#ifndef LIBC_LOADER_H_
#define LIBC_LOADER_H_
#ifndef LIBC_IPC_LOADER_H_
#define LIBC_IPC_LOADER_H_
 
#include <ipc/ipc.h>
 
typedef enum {
LOADER_HELLO = IPC_FIRST_USER_METHOD,
LOADER_GET_TASKID,
LOADER_SET_PATHNAME,
LOADER_SET_ARGS,
LOADER_LOAD,
LOADER_RUN
} fb_request_t;
 
/branches/tracing/uspace/lib/libc/generic/task.c
34,14 → 34,10
*/
 
#include <task.h>
#include <ipc/ipc.h>
#include <ipc/loader.h>
#include <libc.h>
#include <string.h>
#include <stdlib.h>
#include <async.h>
#include <errno.h>
#include <vfs/vfs.h>
#include <loader/loader.h>
 
task_id_t task_get_id(void)
{
52,134 → 48,62
return task_id;
}
 
static int task_spawn_loader(void)
{
int phone_id, rc;
 
rc = __SYSCALL1(SYS_PROGRAM_SPAWN_LOADER, (sysarg_t) &phone_id);
if (rc != 0)
return rc;
 
return phone_id;
}
 
static int loader_set_args(int phone_id, const char *argv[])
{
aid_t req;
ipc_call_t answer;
ipcarg_t rc;
 
const char **ap;
char *dp;
char *arg_buf;
size_t buffer_size;
size_t len;
 
/*
* Serialize the arguments into a single array. First
* compute size of the buffer needed.
*/
ap = argv;
buffer_size = 0;
while (*ap != NULL) {
buffer_size += strlen(*ap) + 1;
++ap;
}
 
arg_buf = malloc(buffer_size);
if (arg_buf == NULL) return ENOMEM;
 
/* Now fill the buffer with null-terminated argument strings */
ap = argv;
dp = arg_buf;
while (*ap != NULL) {
strcpy(dp, *ap);
dp += strlen(*ap) + 1;
 
++ap;
}
 
/* Send serialized arguments to the loader */
 
req = async_send_0(phone_id, LOADER_SET_ARGS, &answer);
rc = ipc_data_write_start(phone_id, (void *)arg_buf, buffer_size);
if (rc != EOK) {
async_wait_for(req, NULL);
return rc;
}
 
async_wait_for(req, &rc);
if (rc != EOK) return rc;
 
/* Free temporary buffer */
free(arg_buf);
 
return EOK;
}
 
/** Create a new task by running an executable from VFS.
/** Create a new task by running an executable from the filesystem.
*
* This is really just a convenience wrapper over the more complicated
* loader API.
*
* @param path pathname of the binary to execute
* @param argv command-line arguments
* @return ID of the newly created task or zero on error.
*/
task_id_t task_spawn(const char *path, const char *argv[])
task_id_t task_spawn(const char *path, char *const argv[])
{
int phone_id;
ipc_call_t answer;
aid_t req;
loader_t *ldr;
task_id_t task_id;
int rc;
ipcarg_t retval;
 
char *pa;
size_t pa_len;
 
pa = absolutize(path, &pa_len);
if (!pa)
/* Spawn a program loader. */
ldr = loader_spawn();
if (ldr == NULL)
return 0;
 
/* Spawn a program loader */
phone_id = task_spawn_loader();
if (phone_id < 0)
return 0;
/* Get task ID. */
rc = loader_get_task_id(ldr, &task_id);
if (rc != EOK)
goto error;
 
/*
* Say hello so that the loader knows the incoming connection's
* phone hash.
*/
rc = async_req_0_0(phone_id, LOADER_HELLO);
/* Send program pathname. */
rc = loader_set_pathname(ldr, path);
if (rc != EOK)
return 0;
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);
if (rc != EOK) {
async_wait_for(req, NULL);
return 1;
}
 
async_wait_for(req, &retval);
if (retval != EOK)
/* Send arguments. */
rc = loader_set_args(ldr, argv);
if (rc != EOK)
goto error;
 
/* Send arguments */
rc = loader_set_args(phone_id, argv);
/* Load the program. */
rc = loader_load_program(ldr);
if (rc != EOK)
goto error;
 
/* Request loader to start the program */
rc = async_req_0_0(phone_id, LOADER_RUN);
/* Run it. */
/* Load the program. */
rc = loader_run(ldr);
if (rc != EOK)
goto error;
 
/* Success */
ipc_hangup(phone_id);
return 1;
 
free(ldr);
return task_id;
 
/* Error exit */
error:
ipc_hangup(phone_id);
loader_abort(ldr);
free(ldr);
 
return 0;
}
 
/branches/tracing/uspace/lib/libc/generic/loader.c
0,0 → 1,266
/*
* 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 <ipc/ipc.h>
#include <ipc/loader.h>
#include <libc.h>
#include <string.h>
#include <stdlib.h>
#include <async.h>
#include <errno.h>
#include <vfs/vfs.h>
#include <loader/loader.h>
 
/** Connect to a new program loader.
*
* Spawns a new program loader task and returns the connection structure.
* @return Pointer to the loader connection structure (should be
* de-allocated using free() after use).
*/
loader_t *loader_spawn(void)
{
int phone_id, rc;
loader_t *ldr;
 
/*
* Ask kernel to spawn a new loader task.
*/
rc = __SYSCALL1(SYS_PROGRAM_SPAWN_LOADER, (sysarg_t) &phone_id);
if (rc != 0)
return NULL;
 
/*
* Say hello so that the loader knows the incoming connection's
* phone hash.
*/
rc = async_req_0_0(phone_id, LOADER_HELLO);
if (rc != EOK)
return NULL;
 
ldr = malloc(sizeof(loader_t));
if (ldr == NULL)
return NULL;
 
ldr->phone_id = phone_id;
return ldr;
}
 
/** Get ID of the new task.
*
* Retrieves the ID of the new task from the loader.
*
* @param ldr Loader connection structure.
* @param task_id Points to a variable where the ID should be stored.
* @return Zero on success or negative error code.
*/
int loader_get_task_id(loader_t *ldr, task_id_t *task_id)
{
ipc_call_t answer;
aid_t req;
int rc;
ipcarg_t retval;
 
/* Get task ID. */
req = async_send_0(ldr->phone_id, LOADER_GET_TASKID, &answer);
rc = ipc_data_read_start(ldr->phone_id, task_id, sizeof(task_id));
if (rc != EOK) {
async_wait_for(req, NULL);
return rc;
}
 
async_wait_for(req, &retval);
return (int)retval;
}
 
/** Set pathname of the program to load.
*
* Sets the name of the program file to load. The name can be relative
* to the current working directory (it will be absolutized before
* sending to the loader).
*
* @param ldr Loader connection structure.
* @param path Pathname of the program file.
* @return Zero on success or negative error code.
*/
int loader_set_pathname(loader_t *ldr, const char *path)
{
ipc_call_t answer;
aid_t req;
int rc;
ipcarg_t retval;
 
char *pa;
size_t pa_len;
 
pa = absolutize(path, &pa_len);
if (!pa)
return 0;
 
/* Send program pathname */
req = async_send_0(ldr->phone_id, LOADER_SET_PATHNAME, &answer);
rc = ipc_data_write_start(ldr->phone_id, (void *)pa, pa_len);
if (rc != EOK) {
async_wait_for(req, NULL);
return rc;
}
 
free(pa);
 
async_wait_for(req, &retval);
return (int)retval;
}
 
 
/** Set command-line arguments for the program.
*
* Sets the vector of command-line arguments to be passed to the loaded
* program. By convention, the very first argument is typically the same as
* the command used to execute the program.
*
* @param ldr Loader connection structure.
* @param argv NULL-terminated array of pointers to arguments.
* @return Zero on success or negative error code.
*/
int loader_set_args(loader_t *ldr, char *const argv[])
{
aid_t req;
ipc_call_t answer;
ipcarg_t rc;
 
char *const *ap;
char *dp;
char *arg_buf;
size_t buffer_size;
 
/*
* Serialize the arguments into a single array. First
* compute size of the buffer needed.
*/
ap = argv;
buffer_size = 0;
while (*ap != NULL) {
buffer_size += strlen(*ap) + 1;
++ap;
}
 
arg_buf = malloc(buffer_size);
if (arg_buf == NULL) return ENOMEM;
 
/* Now fill the buffer with null-terminated argument strings */
ap = argv;
dp = arg_buf;
while (*ap != NULL) {
strcpy(dp, *ap);
dp += strlen(*ap) + 1;
 
++ap;
}
 
/* Send serialized arguments to the loader */
 
req = async_send_0(ldr->phone_id, LOADER_SET_ARGS, &answer);
rc = ipc_data_write_start(ldr->phone_id, (void *)arg_buf, buffer_size);
if (rc != EOK) {
async_wait_for(req, NULL);
return rc;
}
 
async_wait_for(req, &rc);
if (rc != EOK) return rc;
 
/* Free temporary buffer */
free(arg_buf);
 
return EOK;
}
 
/** Instruct loader to load the program.
*
* If this function succeeds, the program has been successfully loaded
* and is ready to be executed.
*
* @param ldr Loader connection structure.
* @return Zero on success or negative error code.
*/
int loader_load_program(loader_t *ldr)
{
int rc;
 
rc = async_req_0_0(ldr->phone_id, LOADER_LOAD);
if (rc != EOK)
return rc;
 
return EOK;
}
 
/** Instruct loader to execute the program.
*
* Note that this function blocks until the loader actually replies
* so you cannot expect this function to return if you are debugging
* the task and its thread is stopped.
*
* After using this function, no further operations must be performed
* on the loader structure. It should be de-allocated using free().
*
* @param ldr Loader connection structure.
* @return Zero on success or negative error code.
*/
int loader_run(loader_t *ldr)
{
int rc;
 
rc = async_req_0_0(ldr->phone_id, LOADER_RUN);
if (rc != EOK)
return rc;
 
return EOK;
}
 
/** Cancel the loader session.
*
* Tells the loader not to load any program and terminate.
* After using this function, no further operations must be performed
* on the loader structure. It should be de-allocated using free().
*
* @param ldr Loader connection structure.
* @return Zero on success or negative error code.
*/
void loader_abort(loader_t *ldr)
{
ipc_hangup(ldr->phone_id);
ldr->phone_id = 0;
}
 
/** @}
*/
/branches/tracing/uspace/lib/libc/generic/udebug.c
57,10 → 57,16
int udebug_thread_read(int phoneid, void *buffer, size_t n,
size_t *copied, size_t *needed)
{
unsigned dest_addr;
ipcarg_t a_copied, a_needed;
int rc;
 
return async_req_3_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_THREAD_READ,
(sysarg_t)buffer, n, &dest_addr, copied, needed);
rc = async_req_3_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_THREAD_READ,
(sysarg_t)buffer, n, NULL, &a_copied, &a_needed);
 
*copied = (size_t)a_copied;
*needed = (size_t)a_needed;
 
return rc;
}
 
int udebug_mem_read(int phoneid, void *buffer, uintptr_t addr, size_t n)
96,8 → 102,14
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);
ipcarg_t a_ev_type;
int rc;
 
rc = async_req_2_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_GO,
tid, &a_ev_type, val0, val1);
 
*ev_type = a_ev_type;
return rc;
}
 
int udebug_stop(int phoneid, thash_t tid)
/branches/tracing/uspace/lib/libc/generic/vfs/vfs.c
599,6 → 599,7
cwd_path = pa;
cwd_len = pa_len;
futex_up(&cwd_futex);
return EOK;
}
 
char *getcwd(char *buf, size_t size)
/branches/tracing/uspace/lib/libc/Makefile
71,6 → 71,7
generic/sysinfo.c \
generic/ipc.c \
generic/async.c \
generic/loader.c \
generic/getopt.c \
generic/libadt/list.o \
generic/libadt/hash_table.o \
/branches/tracing/uspace/srv/loader/main.c
46,6 → 46,7
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <bool.h>
#include <fcntl.h>
#include <sys/types.h>
#include <ipc/ipc.h>
77,6 → 78,33
/** Buffer holding all arguments */
static char *arg_buf = NULL;
 
static elf_info_t prog_info;
static elf_info_t interp_info;
 
static bool is_dyn_linked;
 
 
static void 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
191,20 → 219,16
argv[n] = NULL;
}
 
 
/** Load and run the previously selected program.
/** Load the previously selected program.
*
* @param rid
* @param request
* @return 0 on success, !0 on error.
*/
static int loader_run(ipc_callid_t rid, ipc_call_t *request)
static int loader_load(ipc_callid_t rid, ipc_call_t *request)
{
int rc;
 
elf_info_t prog_info;
elf_info_t interp_info;
 
// printf("Load program '%s'\n", pathname);
 
rc = elf_load_file(pathname, 0, &prog_info);
224,9 → 248,8
/* Statically linked program */
// printf("Run statically linked program\n");
// printf("entry point: 0x%llx\n", prog_info.entry);
is_dyn_linked = false;
ipc_answer_0(rid, EOK);
close_console();
elf_run(&prog_info, &pcb);
return 0;
}
 
244,17 → 267,40
pcb.rtld_dynamic = interp_info.dynamic;
pcb.rtld_bias = RTLD_BIAS;
 
printf("run dynamic linker\n");
printf("entry point: 0x%llx\n", interp_info.entry);
close_console();
 
is_dyn_linked = true;
ipc_answer_0(rid, EOK);
elf_run(&interp_info, &pcb);
 
/* Not reached */
return 0;
}
 
 
/** Run the previously loaded program.
*
* @param rid
* @param request
* @return 0 on success, !0 on error.
*/
static void loader_run(ipc_callid_t rid, ipc_call_t *request)
{
if (is_dyn_linked == true) {
/* Dynamically linked program */
printf("run dynamic linker\n");
printf("entry point: 0x%llx\n", interp_info.entry);
close_console();
 
ipc_answer_0(rid, EOK);
elf_run(&interp_info, &pcb);
 
} else {
/* Statically linked program */
close_console();
ipc_answer_0(rid, EOK);
elf_run(&prog_info, &pcb);
}
 
/* Not reached */
}
 
/** Handle loader connection.
*
* Receive and carry out commands (of which the last one should be
271,18 → 317,23
 
while (1) {
callid = async_get_call(&call);
// 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;
case LOADER_SET_ARGS:
loader_set_args(callid, &call);
continue;
case LOADER_LOAD:
loader_load(callid, &call);
continue;
case LOADER_RUN:
loader_run(callid, &call);
exit(0);
continue;
/* Not reached */
default:
retval = ENOENT;
break;
/branches/tracing/boot/arch/sparc64/loader/Makefile
105,6 → 105,7
$(USPACEDIR)/app/trace/trace \
$(USPACEDIR)/app/tetris/tetris \
$(USPACEDIR)/app/tester/tester \
$(USPACEDIR)/app/trace/trace \
$(USPACEDIR)/app/bdsh/bdsh \
$(USPACEDIR)/app/klog/klog