eclair: support for direct memory inspection
This commit is contained in:
@ -6,6 +6,7 @@ VPATH=@abs_srcdir@
|
|||||||
TARGET=mcexec
|
TARGET=mcexec
|
||||||
@uncomment_if_ENABLE_MEMDUMP@TARGET+=eclair
|
@uncomment_if_ENABLE_MEMDUMP@TARGET+=eclair
|
||||||
LIBS=@LIBS@
|
LIBS=@LIBS@
|
||||||
|
IHKDIR ?= $(VPATH)/../../../ihk/linux/include/
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ mcexec: mcexec.c
|
|||||||
$(CC) -I${KDIR} $(CFLAGS) $(EXTRA_CFLAGS) -fPIE -pie -lrt -pthread -o $@ $^ $(EXTRA_OBJS)
|
$(CC) -I${KDIR} $(CFLAGS) $(EXTRA_CFLAGS) -fPIE -pie -lrt -pthread -o $@ $^ $(EXTRA_OBJS)
|
||||||
|
|
||||||
eclair: eclair.c
|
eclair: eclair.c
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
|
$(CC) $(CFLAGS) -I${IHKDIR} -o $@ $^ $(LIBS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) $(TARGET) *.o
|
$(RM) $(TARGET) *.o
|
||||||
|
|||||||
@ -16,20 +16,8 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
/* From ihk/linux/include/ihk/ihk_host_user.h */
|
#include <ihk/ihk_host_user.h>
|
||||||
#define PHYS_CHUNKS_DESC_SIZE 8192
|
|
||||||
|
|
||||||
struct dump_mem_chunk {
|
|
||||||
unsigned long addr;
|
|
||||||
unsigned long size;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct dump_mem_chunks_s {
|
|
||||||
int nr_chunks;
|
|
||||||
struct dump_mem_chunk chunks[];
|
|
||||||
} dump_mem_chunks_t;
|
|
||||||
/* ---------- */
|
|
||||||
|
|
||||||
#define CPU_TID_BASE 1000000
|
#define CPU_TID_BASE 1000000
|
||||||
|
|
||||||
@ -39,6 +27,10 @@ struct options {
|
|||||||
char *kernel_path;
|
char *kernel_path;
|
||||||
char *dump_path;
|
char *dump_path;
|
||||||
char *log_path;
|
char *log_path;
|
||||||
|
int interactive;
|
||||||
|
int os_id;
|
||||||
|
int mcos_fd;
|
||||||
|
int print_idle;
|
||||||
}; /* struct options */
|
}; /* struct options */
|
||||||
|
|
||||||
struct thread_info {
|
struct thread_info {
|
||||||
@ -56,7 +48,7 @@ struct thread_info {
|
|||||||
int tid;
|
int tid;
|
||||||
int cpu;
|
int cpu;
|
||||||
int lcpu;
|
int lcpu;
|
||||||
int padding;
|
int idle;
|
||||||
uintptr_t process;
|
uintptr_t process;
|
||||||
uintptr_t clv;
|
uintptr_t clv;
|
||||||
uintptr_t x86_clv;
|
uintptr_t x86_clv;
|
||||||
@ -150,7 +142,21 @@ static int read_mem(uintptr_t va, void *buf, size_t size) {
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opt.interactive) {
|
||||||
|
dumpargs_t args;
|
||||||
|
|
||||||
|
args.cmd = DUMP_READ;
|
||||||
|
args.start = pa;
|
||||||
|
args.size = size;
|
||||||
|
args.buf = buf;
|
||||||
|
|
||||||
|
error = ioctl(opt.mcos_fd, IHK_OS_DUMP, &args);
|
||||||
|
}
|
||||||
|
else {
|
||||||
error = read_physmem(pa, buf, size);
|
error = read_physmem(pa, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
perror("read_mem:read_physmem");
|
perror("read_mem:read_physmem");
|
||||||
return 1;
|
return 1;
|
||||||
@ -256,6 +262,7 @@ static int setup_threads(void) {
|
|||||||
perror("num_processors");
|
perror("num_processors");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
printf("%s: num_processors: %d\n", __FUNCTION__, num_processors);
|
||||||
|
|
||||||
error = read_symbol_64("locals", &locals);
|
error = read_symbol_64("locals", &locals);
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -278,71 +285,16 @@ static int setup_threads(void) {
|
|||||||
ihk_mc_switch_context = lookup_symbol("ihk_mc_switch_context");
|
ihk_mc_switch_context = lookup_symbol("ihk_mc_switch_context");
|
||||||
if (0) printf("ihk_mc_switch_context: %lx\n", ihk_mc_switch_context);
|
if (0) printf("ihk_mc_switch_context: %lx\n", ihk_mc_switch_context);
|
||||||
|
|
||||||
/* Set up idle threads first */
|
|
||||||
for (cpu = 0; cpu < num_processors; ++cpu) {
|
|
||||||
uintptr_t v;
|
|
||||||
uintptr_t thread;
|
|
||||||
uintptr_t proc;
|
|
||||||
int pid;
|
|
||||||
int tid;
|
|
||||||
struct thread_info *ti;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
v = clv + (cpu * K(CPU_LOCAL_VAR_SIZE));
|
|
||||||
|
|
||||||
ti = malloc(sizeof(*ti));
|
|
||||||
if (!ti) {
|
|
||||||
perror("malloc");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
thread = v+K(IDLE_THREAD_OFFSET);
|
|
||||||
|
|
||||||
error = read_64(thread+K(PROC_OFFSET), &proc);
|
|
||||||
if (error) {
|
|
||||||
perror("proc");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = read_32(thread+K(STATUS_OFFSET), &status);
|
|
||||||
if (error) {
|
|
||||||
perror("status");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = read_32(proc+K(PID_OFFSET), &pid);
|
|
||||||
if (error) {
|
|
||||||
perror("pid");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = read_32(thread+K(TID_OFFSET), &tid);
|
|
||||||
if (error) {
|
|
||||||
perror("tid");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ti->next = NULL;
|
|
||||||
ti->status = status;
|
|
||||||
ti->pid = pid;
|
|
||||||
ti->tid = tid;
|
|
||||||
ti->cpu = cpu;
|
|
||||||
ti->lcpu = cpu;
|
|
||||||
ti->process = thread;
|
|
||||||
ti->clv = v;
|
|
||||||
ti->x86_clv = locals + locals_span*cpu;
|
|
||||||
|
|
||||||
*titailp = ti;
|
|
||||||
titailp = &ti->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (cpu = 0; cpu < num_processors; ++cpu) {
|
for (cpu = 0; cpu < num_processors; ++cpu) {
|
||||||
uintptr_t v;
|
uintptr_t v;
|
||||||
uintptr_t head;
|
uintptr_t head;
|
||||||
uintptr_t entry;
|
uintptr_t entry;
|
||||||
|
uintptr_t idle;
|
||||||
|
|
||||||
v = clv + (cpu * K(CPU_LOCAL_VAR_SIZE));
|
v = clv + (cpu * K(CPU_LOCAL_VAR_SIZE));
|
||||||
|
|
||||||
|
idle = v+K(IDLE_THREAD_OFFSET);
|
||||||
|
|
||||||
error = read_64(v+K(CURRENT_OFFSET), ¤t);
|
error = read_64(v+K(CURRENT_OFFSET), ¤t);
|
||||||
if (error) {
|
if (error) {
|
||||||
perror("current");
|
perror("current");
|
||||||
@ -400,15 +352,19 @@ static int setup_threads(void) {
|
|||||||
ti->status = status;
|
ti->status = status;
|
||||||
ti->pid = pid;
|
ti->pid = pid;
|
||||||
ti->tid = tid;
|
ti->tid = tid;
|
||||||
ti->cpu = (thread == current)? cpu: -1;
|
ti->cpu = (thread == current) ? cpu : -1;
|
||||||
ti->lcpu = cpu;
|
ti->lcpu = cpu;
|
||||||
ti->process = thread;
|
ti->process = thread;
|
||||||
|
ti->idle = 0;
|
||||||
ti->clv = v;
|
ti->clv = v;
|
||||||
ti->x86_clv = locals + locals_span*cpu;
|
ti->x86_clv = locals + locals_span*cpu;
|
||||||
|
|
||||||
*titailp = ti;
|
*titailp = ti;
|
||||||
titailp = &ti->next;
|
titailp = &ti->next;
|
||||||
|
|
||||||
|
if (!curr_thread)
|
||||||
|
curr_thread = ti;
|
||||||
|
next_thread:
|
||||||
error = read_64(entry, &entry);
|
error = read_64(entry, &entry);
|
||||||
if (error) {
|
if (error) {
|
||||||
perror("process2");
|
perror("process2");
|
||||||
@ -417,8 +373,78 @@ static int setup_threads(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set up idle threads */
|
||||||
|
if (opt.print_idle) {
|
||||||
|
for (cpu = 0; cpu < num_processors; ++cpu) {
|
||||||
|
uintptr_t v;
|
||||||
|
uintptr_t thread;
|
||||||
|
uintptr_t proc;
|
||||||
|
int pid;
|
||||||
|
int tid;
|
||||||
|
struct thread_info *ti;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
v = clv + (cpu * K(CPU_LOCAL_VAR_SIZE));
|
||||||
|
|
||||||
|
error = read_64(v+K(CURRENT_OFFSET), ¤t);
|
||||||
|
if (error) {
|
||||||
|
perror("current");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ti = malloc(sizeof(*ti));
|
||||||
|
if (!ti) {
|
||||||
|
perror("malloc");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread = v+K(IDLE_THREAD_OFFSET);
|
||||||
|
|
||||||
|
error = read_64(thread+K(PROC_OFFSET), &proc);
|
||||||
|
if (error) {
|
||||||
|
perror("proc");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = read_32(thread+K(STATUS_OFFSET), &status);
|
||||||
|
if (error) {
|
||||||
|
perror("status");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = read_32(proc+K(PID_OFFSET), &pid);
|
||||||
|
if (error) {
|
||||||
|
perror("pid");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = read_32(thread+K(TID_OFFSET), &tid);
|
||||||
|
if (error) {
|
||||||
|
perror("tid");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ti->next = NULL;
|
||||||
|
ti->status = status;
|
||||||
|
ti->pid = 1;
|
||||||
|
ti->tid = 2000000000 + tid;
|
||||||
|
ti->cpu = (thread == current) ? cpu : -1;
|
||||||
|
ti->lcpu = cpu;
|
||||||
|
ti->process = thread;
|
||||||
|
ti->idle = 1;
|
||||||
|
ti->clv = v;
|
||||||
|
ti->x86_clv = locals + locals_span*cpu;
|
||||||
|
|
||||||
|
*titailp = ti;
|
||||||
|
titailp = &ti->next;
|
||||||
|
|
||||||
|
if (!curr_thread)
|
||||||
|
curr_thread = ti;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!tihead) {
|
if (!tihead) {
|
||||||
printf("thread not found. cpu mode forcibly\n");
|
printf("No threads found, forcing CPU mode.\n");
|
||||||
opt.cpu = 1;
|
opt.cpu = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,6 +485,7 @@ static int setup_threads(void) {
|
|||||||
ti->tid = CPU_TID_BASE + cpu;
|
ti->tid = CPU_TID_BASE + cpu;
|
||||||
ti->cpu = cpu;
|
ti->cpu = cpu;
|
||||||
ti->process = current;
|
ti->process = current;
|
||||||
|
ti->idle = 1;
|
||||||
ti->clv = v;
|
ti->clv = v;
|
||||||
ti->x86_clv = locals + locals_span*cpu;
|
ti->x86_clv = locals + locals_span*cpu;
|
||||||
|
|
||||||
@ -471,6 +498,8 @@ static int setup_threads(void) {
|
|||||||
printf("thread not found\n");
|
printf("thread not found\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!curr_thread)
|
||||||
curr_thread = tihead;
|
curr_thread = tihead;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -713,18 +742,21 @@ static void command(char *cmd, char *res) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if (regs[17] > MAP_KERNEL) {}
|
||||||
pu8 = (void *)®s;
|
pu8 = (void *)®s;
|
||||||
for (i = 0; i < sizeof(regs)-4; ++i) {
|
for (i = 0; i < sizeof(regs)-4; ++i) {
|
||||||
rbp += sprintf(rbp, "%02x", pu8[i]);
|
rbp += sprintf(rbp, "%02x", pu8[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
else if (!strcmp(p, "mffffffff80018a82,1")) {
|
else if (!strcmp(p, "mffffffff80018a82,1")) {
|
||||||
rbp += sprintf(rbp, "b8");
|
rbp += sprintf(rbp, "b8");
|
||||||
}
|
}
|
||||||
else if (!strcmp(p, "mffffffff80018a82,9")) {
|
else if (!strcmp(p, "mffffffff80018a82,9")) {
|
||||||
rbp += sprintf(rbp, "b8f2ffffff41564155");
|
rbp += sprintf(rbp, "b8f2ffffff41564155");
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
else if (!strncmp(p, "m", 1)) {
|
else if (!strncmp(p, "m", 1)) {
|
||||||
int n;
|
int n;
|
||||||
uintptr_t start;
|
uintptr_t start;
|
||||||
@ -821,25 +853,29 @@ static void command(char *cmd, char *res) {
|
|||||||
}
|
}
|
||||||
q = buf;
|
q = buf;
|
||||||
if (ti->status & PS_RUNNING) {
|
if (ti->status & PS_RUNNING) {
|
||||||
q += sprintf(q, "running on cpu%d", ti->cpu);
|
q += sprintf(q, "%srunning on cpu %d",
|
||||||
|
ti->idle ? "idle " : "", ti->cpu);
|
||||||
}
|
}
|
||||||
else if (ti->status & (PS_INTERRUPTIBLE | PS_UNINTERRUPTIBLE)) {
|
else if (ti->status & (PS_INTERRUPTIBLE | PS_UNINTERRUPTIBLE)) {
|
||||||
q += sprintf(q, "waiting on cpu%d", ti->lcpu);
|
q += sprintf(q, "%swaiting on cpu %d",
|
||||||
|
ti->idle ? "idle " : "", ti->lcpu);
|
||||||
}
|
}
|
||||||
else if (ti->status & PS_STOPPED) {
|
else if (ti->status & PS_STOPPED) {
|
||||||
q += sprintf(q, "stopped on cpu%d", ti->lcpu);
|
q += sprintf(q, "%sstopped on cpu %d",
|
||||||
|
ti->idle ? "idle " : "", ti->lcpu);
|
||||||
}
|
}
|
||||||
else if (ti->status & PS_TRACED) {
|
else if (ti->status & PS_TRACED) {
|
||||||
q += sprintf(q, "traced on cpu%d", ti->lcpu);
|
q += sprintf(q, "%straced on cpu %d",
|
||||||
|
ti->idle ? "idle " : "", ti->lcpu);
|
||||||
}
|
}
|
||||||
else if (ti->status == CS_IDLE) {
|
else if (ti->status == CS_IDLE) {
|
||||||
q += sprintf(q, "cpu%d idle", ti->cpu);
|
q += sprintf(q, "cpu %d idle", ti->cpu);
|
||||||
}
|
}
|
||||||
else if (ti->status == CS_RUNNING) {
|
else if (ti->status == CS_RUNNING) {
|
||||||
q += sprintf(q, "cpu%d running", ti->cpu);
|
q += sprintf(q, "cpu %d running", ti->cpu);
|
||||||
}
|
}
|
||||||
else if (ti->status == CS_RESERVED) {
|
else if (ti->status == CS_RESERVED) {
|
||||||
q += sprintf(q, "cpu%d reserved", ti->cpu);
|
q += sprintf(q, "cpu %d reserved", ti->cpu);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
q += sprintf(q, "status=%#x", ti->status);
|
q += sprintf(q, "status=%#x", ti->status);
|
||||||
@ -859,11 +895,12 @@ static void options(int argc, char *argv[]) {
|
|||||||
memset(&opt, 0, sizeof(opt));
|
memset(&opt, 0, sizeof(opt));
|
||||||
opt.kernel_path = "./mckernel.img";
|
opt.kernel_path = "./mckernel.img";
|
||||||
opt.dump_path = "./mcdump";
|
opt.dump_path = "./mcdump";
|
||||||
|
opt.mcos_fd = -1;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
c = getopt(argc, argv, "cd:hk:");
|
c = getopt(argc, argv, "ilcd:hk:o:");
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -881,12 +918,32 @@ static void options(int argc, char *argv[]) {
|
|||||||
case 'd':
|
case 'd':
|
||||||
opt.dump_path = optarg;
|
opt.dump_path = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'i':
|
||||||
|
opt.interactive = 1;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
opt.os_id = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
opt.print_idle = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (optind < argc) {
|
if (optind < argc) {
|
||||||
opt.help = 1;
|
opt.help = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opt.interactive) {
|
||||||
|
char fn[128];
|
||||||
|
sprintf(fn, "/dev/mcos%d", opt.os_id);
|
||||||
|
|
||||||
|
opt.mcos_fd = open(fn, O_RDONLY);
|
||||||
|
if (opt.mcos_fd < 0) {
|
||||||
|
perror("open");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} /* options() */
|
} /* options() */
|
||||||
|
|
||||||
@ -969,7 +1026,7 @@ int main(int argc, char *argv[]) {
|
|||||||
uint8_t sum;
|
uint8_t sum;
|
||||||
uint8_t check;
|
uint8_t check;
|
||||||
static char lbuf[1024];
|
static char lbuf[1024];
|
||||||
static char rbuf[1024];
|
static char rbuf[8192];
|
||||||
static char cbuf[3];
|
static char cbuf[3];
|
||||||
char *lbp;
|
char *lbp;
|
||||||
char *p;
|
char *p;
|
||||||
|
|||||||
@ -2394,7 +2394,9 @@ static void idle(void)
|
|||||||
cpu_enable_interrupt();
|
cpu_enable_interrupt();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
cpu_local_var(current)->status = PS_STOPPED;
|
||||||
schedule();
|
schedule();
|
||||||
|
cpu_local_var(current)->status = PS_RUNNING;
|
||||||
cpu_disable_interrupt();
|
cpu_disable_interrupt();
|
||||||
|
|
||||||
/* See if we need to migrate a process somewhere */
|
/* See if we need to migrate a process somewhere */
|
||||||
@ -2440,7 +2442,9 @@ static void idle(void)
|
|||||||
v->status == CPU_STATUS_RESERVED) {
|
v->status == CPU_STATUS_RESERVED) {
|
||||||
/* No work to do? Consolidate the kmalloc free list */
|
/* No work to do? Consolidate the kmalloc free list */
|
||||||
kmalloc_consolidate_free_list();
|
kmalloc_consolidate_free_list();
|
||||||
|
cpu_local_var(current)->status = PS_INTERRUPTIBLE;
|
||||||
cpu_safe_halt();
|
cpu_safe_halt();
|
||||||
|
cpu_local_var(current)->status = PS_RUNNING;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cpu_enable_interrupt();
|
cpu_enable_interrupt();
|
||||||
|
|||||||
Reference in New Issue
Block a user