/** @addtogroup sctrace
* @{
*/
/** @file
*/
#include <stdio.h>
#include <unistd.h>
#include <syscall.h>
#include <ipc/ipc.h>
#include <fibril.h>
#include <errno.h>
#include <udebug.h>
#include <async.h>
#include "syscalls.h"
#include "ipc.h"
#include "errors.h"
#include "debug_api.h"
#define THBUF_SIZE 64
unsigned thread_hash_buf[THBUF_SIZE];
unsigned n_threads;
int next_thread_id;
int phoneid;
int abort_trace;
void thread_trace_start(unsigned thread_hash);
int task_connect(int taskid)
{
int rc;
printf("ipc_connect_task(%d)...\n", taskid
);
rc = ipc_connect_kbox(taskid);
phoneid = rc;
if (rc < 0) return rc;
rc = debug_begin(phoneid);
if (rc < 0) return rc;
return 0;
}
int get_thread_list(void)
{
int rc;
int tb_copied;
int tb_needed;
int i;
printf("send IPC_M_DEBUG_THREAD_READ message\n");
rc = debug_thread_read(phoneid, (unsigned)thread_hash_buf,
THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed);
if (rc < 0) return rc;
n_threads = tb_copied / sizeof(unsigned);
for (i=0; i<n_threads; i++) {
printf(" %u", thread_hash_buf
[i
]);
}
printf("\ntotal of %u threads\n", tb_needed
/sizeof(unsigned));
return 0;
}
void print_sc_retval(int retval, rv_type_t rv_type)
{
if (rv_type == RV_INTEGER) {
} else if (rv_type == RV_HASH) {
} else if (rv_type == RV_ERRNO) {
if (retval >= -15 && retval <= 0) {
err_desc[retval].name,
err_desc[retval].desc);
} else {
}
} else if (rv_type == RV_INT_ERRNO) {
if (retval >= -15 && retval < 0) {
err_desc[retval].name,
err_desc[retval].desc);
} else {
}
}
}
void print_sc_args(unsigned *sc_args, int n)
{
int i;
if (n
> 0) printf("%d", sc_args
[0]);
for (i=1; i<n; i++) {
}
}
void sc_ipc_call_async_fast(unsigned *sc_args)
{
ipc_call_t call;
int phoneid;
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);
ipc_parse_call_out(phoneid, &call);
}
void sc_ipc_call_async_slow(unsigned *sc_args)
{
ipc_call_t call;
int rc;
memset(&call
, 0, sizeof(call
));
rc = debug_mem_read(phoneid, &call.args, sc_args[1], sizeof(call.args));
if (rc >= 0) {
ipc_parse_call_out(sc_args[0], &call);
}
}
void sc_ipc_wait(unsigned *sc_args, int sc_rc)
{
ipc_call_t call;
int rc;
if (sc_rc == 0) return 0;
memset(&call
, 0, sizeof(call
));
rc = debug_mem_read(phoneid, &call, sc_args[0], sizeof(call));
printf("debug_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) {
ipc_parse_call_in(&call);
}
}
void event_syscall(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 = debug_args_read(phoneid, thread_hash, sc_args);
async_serialize_start();
if (rc < 0) {
async_serialize_end();
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);
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);
break;
case SYS_IPC_CALL_ASYNC_SLOW:
sc_ipc_call_async_slow(sc_args);
break;
case SYS_IPC_WAIT:
sc_ipc_wait(sc_args, sc_rc);
break;
default:
break;
}
async_serialize_end();
}
void event_new_thread(unsigned hash)
{
async_serialize_start();
printf("new thread, hash 0x%x\n", hash
);
async_serialize_end();
thread_trace_start(hash);
}
void 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("trace_loop(%d)\n", thread_id
);
while (!abort_trace) {
/* Run thread until an event occurs */
rc = debug_go(phoneid, thread_hash,
&ev_type, &val0, &val1);
printf("rc = %d, ev_type=%d\n", rc
, ev_type
);
if (ev_type == UDEBUG_EVENT_FINISHED) {
printf("thread %u debugging finished\n", thread_id
);
break;
}
if (rc >= 0) {
switch (ev_type) {
case UDEBUG_EVENT_SYSCALL:
event_syscall(thread_id, thread_hash, val0, (int)val1);
break;
case UDEBUG_EVENT_NEW_THREAD:
event_new_thread(val0);
break;
default:
printf("unknown event type %d\n", ev_type
);
break;
}
}
}
printf("trace_loop(%d) exiting\n", thread_id
);
}
void thread_trace_start(unsigned thread_hash)
{
fid_t fid;
fid = fibril_create(trace_loop, (void *)thread_hash);
if (fid == 0) {
printf("Warning: Failed creating fibril\n");
}
fibril_add_ready(fid);
}
void trace_active_task(void)
{
int taskid;
int i;
int rc;
printf("Press 'c' to connect\n");
taskid = 14;
rc = task_connect(taskid);
if (rc < 0) {
printf("Failed to connect to task %d\n", taskid
);
return;
}
printf("Connected to task %d\n", taskid
);
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]);
}
printf("terminate debugging session...\n");
abort_trace = 1;
debug_end(phoneid);
ipc_hangup(phoneid);
return;
}
int main(void)
{
next_thread_id = 1;
while (1) {
trace_active_task();
}
}
/** @}
*/