//branches/snapshot/kernel/generic/include/udebug/udebug.h |
---|
105,6 → 105,18 |
*/ |
UDEBUG_M_MEM_READ, |
UDEBUG_M_TASK_MEM_AREAS_READ, |
UDEBUG_M_THREAD_COPY_KSTACK, |
UDEBUG_M_THREAD_GET_THREAD_STRUCT, |
UDEBUG_M_MEM_WRITE, |
UDEBUG_M_THREAD_RESTORE_THREAD_STRUCT, |
UDEBUG_M_RESTORE_KSTACK, |
} udebug_method_t; |
//branches/snapshot/kernel/generic/include/udebug/udebug_ops.h |
---|
49,6 → 49,14 |
int udebug_mem_read(unative_t uspace_addr, size_t n, void **buffer); |
/* CHECKPOINTING */ |
int udebug_task_get_memory_areas(void **buffer, size_t buf_size, size_t *n); |
int udebug_mem_write(void *buffer, void *start, size_t n); |
int udebug_copy_kstack(void *kstack, void **buffer, size_t n); |
int udebug_thread_get_thread_struct(thread_t *t, void **buffer); |
int udebug_restore_thread_struct(void *buffer, thread_t *t_old); |
int udebug_restore_kstack(void *buffer, size_t size, thread_t *t); |
#endif |
/** @} |
//branches/snapshot/kernel/generic/src/udebug/udebug_ipc.c |
---|
285,6 → 285,159 |
ipc_answer(&TASK->kb.box, call); |
} |
/**************************/ |
/*** CHECKPOINTING ***/ |
/**************************/ |
static void udebug_receive_thread_get_thread_struct(call_t *call) |
{ |
unative_t to_copy; |
unative_t total_bytes; |
thread_t *t = (thread_t *)IPC_GET_ARG3(call->data); |
void *buffer; |
unative_t uspace_addr = IPC_GET_ARG2(call->data); |
size_t buf_size = IPC_GET_ARG4(call->data); |
if (buf_size < sizeof(thread_t)) |
{ |
to_copy = 0; |
total_bytes = sizeof(thread_t); |
} |
else |
{ |
udebug_thread_get_thread_struct(t, &buffer); |
to_copy = sizeof(thread_t); |
total_bytes = sizeof(thread_t); |
} |
IPC_SET_RETVAL(call->data, 0); |
IPC_SET_ARG1(call->data, uspace_addr); |
IPC_SET_ARG2(call->data, to_copy); |
IPC_SET_ARG3(call->data, total_bytes); |
if (to_copy > 0) |
call->buffer = buffer; |
else |
call->buffer = NULL; |
ipc_answer(&TASK->kb.box, call); |
} |
static void udebug_receive_thread_copy_kstack(call_t *call) |
{ |
void *buffer; |
unative_t uspace_addr = IPC_GET_ARG2(call->data); |
size_t buf_size = IPC_GET_ARG3(call->data); |
thread_t *t = (thread_t *)IPC_GET_ARG4(call->data); |
size_t copied; |
size_t kstack_size = PAGE_SIZE;//(uintptr_t)t->saved_context.sp - (uintptr_t)t->kstack; |
if (buf_size >= kstack_size) |
{ |
udebug_copy_kstack(t->kstack, &buffer, buf_size); |
copied = kstack_size; |
} |
else |
copied = 0; |
IPC_SET_RETVAL(call->data, 0); |
IPC_SET_ARG1(call->data, uspace_addr); |
IPC_SET_ARG2(call->data, copied); |
IPC_SET_ARG3(call->data, kstack_size); // needed |
if (copied > 0) |
call->buffer = (void *)buffer; |
else |
call->buffer = NULL; |
ipc_answer(&TASK->kb.box, call); |
} |
static void udebug_receive_task_mem_areas_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 */ |
rc = udebug_task_get_memory_areas(&buffer, buf_size, &n); |
if (rc < 0) { |
IPC_SET_RETVAL(call->data, rc); |
ipc_answer(&TASK->kb.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->kb.box, call); |
} |
static void udebug_receive_mem_write(call_t *call) |
{ |
size_t size = (size_t)IPC_GET_ARG3(call->data); |
void *start = (void *)IPC_GET_ARG4(call->data); |
udebug_mem_write(call->buffer, start, size); |
IPC_SET_RETVAL(call->data, 0); |
ipc_answer(&TASK->kb.box, call); |
} |
static void udebug_receive_thread_restore_struct(call_t *call) |
{ |
thread_t *t = (thread_t *)IPC_GET_ARG3(call->data); |
udebug_restore_thread_struct(call->buffer, t); |
IPC_SET_RETVAL(call->data, 0); |
ipc_answer(&TASK->kb.box, call); |
} |
static void udebug_receive_restore_kstack(call_t *call) |
{ |
size_t size = (size_t)IPC_GET_ARG3(call->data); |
thread_t *t = (thread_t *)IPC_GET_ARG4(call->data); |
udebug_restore_kstack(call->buffer, size, t); |
IPC_SET_RETVAL(call->data, 0); |
ipc_answer(&TASK->kb.box, call); |
} |
/** Handle a debug call received on the kernel answerbox. |
* |
* This is called by the kbox servicing thread. Verifies that the sender |
336,6 → 489,26 |
case UDEBUG_M_MEM_READ: |
udebug_receive_mem_read(call); |
break; |
/* CHECKPOINTING */ |
case UDEBUG_M_TASK_MEM_AREAS_READ: |
udebug_receive_task_mem_areas_read(call); |
break; |
case UDEBUG_M_MEM_WRITE: |
udebug_receive_mem_write(call); |
break; |
case UDEBUG_M_THREAD_COPY_KSTACK: |
udebug_receive_thread_copy_kstack(call); |
break; |
case UDEBUG_M_RESTORE_KSTACK: |
udebug_receive_restore_kstack(call); |
break; |
case UDEBUG_M_THREAD_GET_THREAD_STRUCT: |
udebug_receive_thread_get_thread_struct(call); |
break; |
case UDEBUG_M_THREAD_RESTORE_THREAD_STRUCT: |
udebug_receive_thread_restore_struct(call); |
break; |
} |
} |
//branches/snapshot/kernel/generic/src/udebug/udebug_ops.c |
---|
503,5 → 503,155 |
return 0; |
} |
int udebug_thread_get_thread_struct(thread_t *t, void **buffer) |
{ |
ipl_t ipl = interrupts_disable(); |
void *data_buffer = (void *)malloc(sizeof(thread_t), 0); |
memcpy(data_buffer, (void *)t, sizeof(thread_t)); |
*buffer = data_buffer; |
interrupts_restore(ipl); |
return (0); |
} |
int udebug_task_get_memory_areas(void **buffer, size_t buf_size, size_t *n) |
{ |
link_t *cur; |
ipl_t ipl; |
unative_t *areas_buffer; |
size_t max_index; |
as_print(TASK->as); |
areas_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); |
max_index = buf_size / sizeof(unative_t); |
as_t *as = TASK->as; |
mutex_lock(&as->lock); |
/* print out info about address space areas */ |
unsigned int index = 0; |
for (cur = as->as_area_btree.leaf_head.next; |
cur != &as->as_area_btree.leaf_head; cur = cur->next) { |
btree_node_t *node; |
node = list_get_instance(cur, btree_node_t, leaf_link); |
unsigned int i; |
for (i = 0; i < node->keys; i++) { |
if (index >= max_index) |
break; |
as_area_t *area = node->value[i]; |
mutex_lock(&area->lock); |
areas_buffer[index++] = area->base; |
areas_buffer[index++] = area->base + FRAMES2SIZE(area->pages); |
mutex_unlock(&area->lock); |
} |
} |
mutex_unlock(&as->lock); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
mutex_unlock(&TASK->udebug.lock); |
*buffer = areas_buffer; |
*n = (index) * sizeof(unative_t); |
return 0; |
} |
int udebug_copy_kstack(void *kstack, void **buffer, size_t n) |
{ |
ipl_t ipl = interrupts_disable(); |
void *data_buffer = malloc(n, 0); |
memcpy(data_buffer, (void *)kstack, n); |
*buffer = data_buffer; |
interrupts_restore(ipl); |
return 0; |
} |
int udebug_restore_thread_struct(void *buffer, thread_t *t_old) |
{ |
ipl_t ipl = interrupts_disable(); |
thread_t *t_new = (thread_t *)buffer; |
t_old->thread_code = t_new->thread_code; |
printf("old sp: %p, new sp: %p\n", t_old->saved_context.sp, t_new->saved_context.sp); |
printf("old kstack: %p, new kstack: %p\n", t_old->kstack, t_new->kstack); |
t_old->saved_context = t_new->saved_context; |
t_old->saved_context.sp = (uintptr_t)t_old->kstack + ((uintptr_t)t_new->saved_context.sp - (uintptr_t)t_new->kstack); |
t_old->sleep_timeout_context = t_new->sleep_timeout_context; |
t_old->sleep_timeout = t_new->sleep_timeout; |
t_old->timeout_pending = t_new->timeout_pending; |
t_old->in_copy_from_uspace = t_new->in_copy_from_uspace; |
t_old->in_copy_to_uspace = t_new->in_copy_to_uspace; |
t_old->interrupted = t_new->interrupted; |
t_old->call_me = t_new->call_me; |
t_old->call_me_with = t_new->call_me_with; |
t_old->udebug.go_call = t_new->udebug.go_call; |
interrupts_restore(ipl); |
return (0); |
} |
int udebug_mem_write(void *buffer, void *start, size_t n) |
{ |
ipl_t ipl = interrupts_disable(); |
if (((unsigned) start & 0x80000000) == 0) |
copy_to_uspace(start, buffer, n); |
interrupts_restore(ipl); |
return (0); |
} |
int udebug_restore_kstack(void *buffer, size_t size, thread_t *t) |
{ |
ipl_t ipl = interrupts_disable(); |
memcpy(t->kstack + sizeof(the_t), buffer + sizeof(the_t), size - sizeof(the_t)); |
interrupts_restore(ipl); |
return (0); |
} |
/** @} |
*/ |
//branches/snapshot/uspace/app/chkpnt/checkpoint.c |
---|
1,4 → 1,241 |
#include <stdlib.h> |
#include <sysinfo.h> |
#include <stdio.h> |
#include <errno.h> |
#include <sys/stat.h> |
#include <vfs/vfs.h> |
#include <unistd.h> |
#include <fcntl.h> |
#include <ipc/ipc.h> |
#include <sys/types.h> |
#include <malloc.h> |
#include <udebug.h> |
#define THBUF_SIZE 64 |
#define FILE_CHUNK_SIZE 250 |
int spawn_task(char* task, char *argv[]); |
int write_to_disk(void *buffer, size_t n, char *filename); |
int init_disk(); |
int connect_kbox(int task_id, int *kbox_phone_id); |
int store_kstack(int kbox_phone_id, thash_t tid); |
int store_thread_struct(int kbox_phone_id, thash_t tid); |
int checkpoint(unsigned int kbox_phone_id_arg); |
int write_uspace_mem_to_disk(unsigned *buffer, size_t n, uintptr_t start_addr, char *filename); |
int store_uspace_memory_areas_to_disk(int kbox_phone_id); |
int main(int argc, char **argv) |
{ |
char *task = "/app/tetris"; |
char *argv_spawn[2]; |
argv_spawn[0] = task; |
argv_spawn[1] = NULL; |
int task_id = spawn_task(task, argv_spawn); |
checkpoint(task_id); |
return (0); |
} |
int checkpoint(unsigned int task_id) |
{ |
/* Create the directories. */ |
init_disk(); |
int kbox_phone_id; |
connect_kbox(task_id, &kbox_phone_id); |
int dbg_ret; |
dbg_ret = udebug_begin(kbox_phone_id); |
uintptr_t thread_hash_buf[THBUF_SIZE]; |
size_t copied, needed; |
udebug_thread_read(kbox_phone_id, thread_hash_buf, sizeof(thread_hash_buf), &copied, &needed); |
printf("Press a key to store kstack contents...\n"); |
getchar(); |
store_kstack(kbox_phone_id, thread_hash_buf[0]); |
printf("Press a key to store thread structure...\n"); |
getchar(); |
store_thread_struct(kbox_phone_id, thread_hash_buf[0]); |
printf("Press a key to read and write uspace memory contents...\n"); |
getchar(); |
store_uspace_memory_areas_to_disk(kbox_phone_id); |
printf("Press key to FINISH checkpointing...\n"); |
getchar(); |
int rc_end = udebug_end(kbox_phone_id); |
printf("rc end: %i\n", rc_end); |
} |
int spawn_task(char* task, char *argv[]) |
{ |
int task_id = task_spawn(task, argv); |
if (task_id <= 0) |
printf("error spawning\n"); |
printf("spawned task %s with id: %i\n", task, task_id); |
return (task_id); |
} |
int init_disk() |
{ |
int rc; |
if ((rc = mkdir("/mydir", 0)) != 0) |
printf("mkdir() failed.\n"); |
return (rc); |
} |
int connect_kbox(int task_id, int *kbox_phone_id) |
{ |
*kbox_phone_id = ipc_connect_kbox(task_id); |
if (*kbox_phone_id == ENOTSUP) |
printf("not suppported\n"); |
if (*kbox_phone_id < 0) { |
printf("Error connecting\n"); |
printf("ipc_connect_task(%lld) -> %d ", task_id, *kbox_phone_id); |
return (-1); |
} |
return (0); |
} |
int store_kstack(int kbox_phone_id, thash_t tid) |
{ |
size_t copied, needed; |
unsigned tmp[1]; |
udebug_thread_copy_kstack(kbox_phone_id, tid, tmp, sizeof(tmp), &copied, &needed); |
void *kstack_buffer = malloc(needed); |
udebug_thread_copy_kstack(kbox_phone_id, tid, kstack_buffer, needed, &copied, &needed); |
write_to_disk(kstack_buffer, needed, "/mydir/kstack"); |
printf("size of kstack: %p\n", needed); |
free(kstack_buffer); |
return (0); |
} |
int store_thread_struct(int kbox_phone_id, thash_t tid) |
{ |
size_t ts_copied, ts_needed, ts_needed_old; |
udebug_thread_get_thread_struct(kbox_phone_id, tid, NULL, 0, &ts_copied, &ts_needed); |
ts_needed_old = ts_needed; |
void *thread_struct_buffer = malloc(ts_needed); |
udebug_thread_get_thread_struct(kbox_phone_id, tid, thread_struct_buffer, ts_needed, &ts_copied, &ts_needed); |
write_to_disk(thread_struct_buffer, ts_copied, "/mydir/ts"); |
free(thread_struct_buffer); |
return (0); |
} |
int store_uspace_memory_areas_to_disk(int kbox_phone_id) |
{ |
size_t mem_copied, mem_needed; |
unsigned *mem_areas_buf = (unsigned *)malloc(sizeof(unsigned *) * THBUF_SIZE); |
udebug_task_memory_areas_read(kbox_phone_id, mem_areas_buf, THBUF_SIZE*sizeof(unsigned), &mem_copied, &mem_needed); |
int areas = mem_copied / sizeof(unsigned); |
int i; |
for (i=0; i<areas; i+=2) |
{ |
size_t size = mem_areas_buf[i+1] - mem_areas_buf[i]; |
unsigned *mem_read_out = malloc(size); |
udebug_mem_read(kbox_phone_id, mem_read_out, mem_areas_buf[i], size); |
char file_name_buf[25]; |
snprintf(file_name_buf, 25, "/mydir/%i.mem", i); |
printf("Writing area at %p to disk, size: %p.\n", mem_areas_buf[i], size); |
write_uspace_mem_to_disk(mem_read_out, size, mem_areas_buf[i], file_name_buf); |
free(mem_read_out); |
} |
return (0); |
} |
int write_uspace_mem_to_disk(unsigned *buffer, size_t n, uintptr_t start_addr, char *filename) |
{ |
size_t chunk_size = FILE_CHUNK_SIZE*sizeof(unsigned); |
unsigned written = 0; |
int fd0 = open(filename, O_CREAT); |
int cnt; |
uintptr_t tmp[1]; |
tmp[0] = start_addr; |
cnt = write(fd0, tmp, sizeof(tmp)); |
while (written < n) |
{ |
if (n - written < chunk_size) |
chunk_size = n - written; |
cnt = write(fd0, buffer, chunk_size); |
if (cnt < 0) |
{ |
printf("Writing to uspace memory failed! Written %p bytes. Code: %i\n", written, cnt); |
break; |
} |
buffer += (cnt / sizeof(unsigned)); |
written += cnt; |
} |
printf("Written %p bytes. End address: %p\n", written, (unsigned*)((unsigned)start_addr + written)); |
close(fd0); |
return (0); |
} |
int write_to_disk(void *buffer, size_t n, char *filename) |
{ |
size_t chunk_size = FILE_CHUNK_SIZE * sizeof(unsigned); |
printf("Writing to disk, size: %p, filename: %s.\n", n, filename); |
int fd0 = open(filename, O_CREAT); |
size_t written = 0; |
size_t tmp[1]; |
tmp[0] = n; |
write(fd0, tmp, sizeof(tmp)); |
while (written < n) |
{ |
if (n - written < chunk_size) |
{ |
chunk_size = n - written; |
} |
int cnt = write(fd0, buffer, chunk_size); |
if (cnt < 0) |
{ |
printf("Write failed! Code: %i\n", cnt); |
break; |
} |
buffer += cnt; |
written += cnt; |
} |
printf("Written %p bytes.\n", written); |
close(fd0); |
return (0); |
} |
//branches/snapshot/uspace/lib/libc/include/udebug.h |
---|
52,6 → 52,13 |
sysarg_t *val0, sysarg_t *val1); |
int udebug_stop(int phoneid, thash_t tid); |
int udebug_thread_copy_kstack(int phoneid, thash_t tid, void *buffer, size_t buf_size, size_t *copied, size_t *needed); |
int udebug_thread_get_thread_struct(int phoneid, thash_t tid, void *buffer, size_t n, size_t *copied, size_t *needed); |
int udebug_task_memory_areas_read(int phoneid, void *buffer, size_t n, size_t *copied, size_t *needed); |
int udebug_thread_restore_thread_struct(int phoneid, thash_t tid, void *buffer); |
int udebug_mem_write(int phoneid, void* buffer, void* start, size_t n); |
int udebug_restore_kstack(int phoneid, thash_t tid, void *buffer, size_t size); |
#endif |
/** @} |
//branches/snapshot/uspace/lib/libc/generic/udebug.c |
---|
99,5 → 99,59 |
tid); |
} |
int udebug_thread_copy_kstack(int phoneid, thash_t tid, void *buffer, size_t buf_size, size_t *copied, size_t *needed) |
{ |
size_t arg_copied, arg_needed; |
int rc = async_req_4_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_THREAD_COPY_KSTACK, (sysarg_t)buffer, buf_size, tid, NULL, &arg_copied, &arg_needed); |
*copied = arg_copied; |
*needed = arg_needed; |
return (rc); |
} |
int udebug_thread_get_thread_struct(int phoneid, thash_t tid, void *buffer, size_t n, size_t *copied, size_t *needed) |
{ |
ipcarg_t a_copied, a_needed; |
int rc = async_req_4_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_THREAD_GET_THREAD_STRUCT, (sysarg_t)buffer, tid, n, NULL, &a_copied, &a_needed); |
*copied = (size_t)a_copied; |
*needed = (size_t)a_needed; |
return (rc); |
} |
int udebug_task_memory_areas_read(int phoneid, void *buffer, size_t n, size_t *copied, size_t *needed) |
{ |
ipcarg_t a_copied, a_needed; |
int rc; |
rc = async_req_3_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_TASK_MEM_AREAS_READ, |
(sysarg_t)buffer, n, NULL, &a_copied, &a_needed); |
*copied = (size_t)a_copied; |
*needed = (size_t)a_needed; |
return (rc); |
} |
int udebug_thread_restore_thread_struct(int phoneid, thash_t tid, void *buffer) |
{ |
int rc = async_req_3_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_THREAD_RESTORE_THREAD_STRUCT, (sysarg_t)buffer, tid); |
return (rc); |
} |
int udebug_mem_write(int phoneid, void *buffer, void *start, size_t n) |
{ |
return async_req_4_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_MEM_WRITE, (sysarg_t)buffer, n, (sysarg_t)start); |
} |
int udebug_restore_kstack(int phoneid, thash_t tid, void *buffer, size_t size) |
{ |
return async_req_4_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_RESTORE_KSTACK, (sysarg_t)buffer, size, tid); |
} |
/** @} |
*/ |