2011-10-24 22:23:06 +04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "compiler.h"
|
|
|
|
#include "types.h"
|
|
|
|
#include "syscall.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "image.h"
|
|
|
|
|
2011-10-25 21:25:42 +04:00
|
|
|
#include "crtools.h"
|
2011-10-24 22:23:06 +04:00
|
|
|
#include "restorer.h"
|
|
|
|
|
2011-10-25 21:25:42 +04:00
|
|
|
#define get_rt_sigframe_addr(stack) \
|
|
|
|
(struct rt_sigframe *)(stack - sizeof(long))
|
|
|
|
|
2011-10-25 00:01:27 +04:00
|
|
|
#define lea_args_off(p) \
|
|
|
|
do { \
|
|
|
|
asm volatile( \
|
|
|
|
"leaq restore_args__(%%rip), %%rax \n\t" \
|
|
|
|
"movq %%rax, %0 \n\t" \
|
|
|
|
: "=m"(p) \
|
|
|
|
: \
|
|
|
|
: "memory"); \
|
|
|
|
} while (0)
|
|
|
|
|
2011-10-27 18:59:21 +04:00
|
|
|
#define add_ord(c) \
|
|
|
|
do { \
|
|
|
|
if (c < 10) \
|
|
|
|
c += '0'; \
|
|
|
|
else \
|
|
|
|
c += 'a' - 10; \
|
|
|
|
} while (0)
|
|
|
|
|
2011-10-25 21:25:42 +04:00
|
|
|
static void always_inline write_string(char *str)
|
|
|
|
{
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
while (str[len])
|
|
|
|
len++;
|
|
|
|
|
|
|
|
sys_write(1, str, len);
|
|
|
|
}
|
|
|
|
|
2011-10-27 18:59:21 +04:00
|
|
|
static void always_inline write_string_n(char *str)
|
|
|
|
{
|
|
|
|
char new_line = '\n';
|
|
|
|
|
|
|
|
write_string(str);
|
|
|
|
sys_write(1, &new_line, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void always_inline write_hex_n(unsigned long num)
|
|
|
|
{
|
|
|
|
bool tailing = false;
|
|
|
|
unsigned char *s = (unsigned char *)#
|
|
|
|
unsigned char c;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = sizeof(long)/sizeof(char) - 1; i >= 0; i--) {
|
|
|
|
c = (s[i] & 0xf0) >> 4;
|
|
|
|
add_ord(c);
|
|
|
|
sys_write(1, &c, 1);
|
|
|
|
|
|
|
|
c = (s[i] & 0x0f);
|
|
|
|
add_ord(c);
|
|
|
|
sys_write(1, &c, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
c = '\n';
|
|
|
|
sys_write(1, &c, 1);
|
|
|
|
}
|
|
|
|
|
2011-10-24 22:23:06 +04:00
|
|
|
long restorer(long cmd)
|
|
|
|
{
|
2011-10-25 23:36:03 +04:00
|
|
|
long ret = -1;
|
2011-10-24 22:23:06 +04:00
|
|
|
|
|
|
|
asm volatile(
|
|
|
|
"jmp 1f \n\t"
|
|
|
|
"restore_args__: \n\t"
|
|
|
|
".skip "__stringify(RESTORER_ARGS_SIZE)",0 \n\t"
|
|
|
|
"1: \n\t"
|
|
|
|
:
|
|
|
|
:
|
|
|
|
: "memory");
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case RESTORER_CMD__PR_ARG_STRING:
|
|
|
|
{
|
|
|
|
char *str = NULL;
|
|
|
|
|
2011-10-25 00:01:27 +04:00
|
|
|
lea_args_off(str);
|
2011-10-25 23:36:03 +04:00
|
|
|
write_string(str);
|
2011-10-25 00:01:27 +04:00
|
|
|
|
2011-10-25 23:36:03 +04:00
|
|
|
ret = 0;
|
2011-10-24 22:23:06 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RESTORER_CMD__GET_ARG_OFFSET:
|
2011-10-25 00:01:27 +04:00
|
|
|
lea_args_off(ret);
|
2011-10-24 22:23:06 +04:00
|
|
|
break;
|
|
|
|
|
2011-10-26 11:16:00 +04:00
|
|
|
case RESTORER_CMD__GET_SELF_LEN:
|
|
|
|
goto self_len_start;
|
|
|
|
self_len_end:
|
|
|
|
break;
|
|
|
|
|
2011-10-24 23:56:36 +04:00
|
|
|
/*
|
|
|
|
* This one is very special, we never return there
|
|
|
|
* but use sigreturn facility to restore core registers
|
|
|
|
* and jump execution to some predefined ip read from
|
|
|
|
* core file.
|
|
|
|
*/
|
|
|
|
case RESTORER_CMD__RESTORE_CORE:
|
|
|
|
{
|
2011-10-26 00:30:41 +04:00
|
|
|
struct restore_core_args *args;
|
2011-10-27 18:59:21 +04:00
|
|
|
int fd_self_vmas;
|
2011-10-25 21:25:42 +04:00
|
|
|
int fd_core;
|
|
|
|
|
|
|
|
struct core_entry core_entry;
|
2011-10-26 00:30:41 +04:00
|
|
|
struct vma_entry vma_entry;
|
|
|
|
u64 va;
|
|
|
|
|
2011-10-25 21:25:42 +04:00
|
|
|
struct rt_sigframe *frame;
|
2011-10-26 11:16:00 +04:00
|
|
|
|
2011-10-26 00:30:41 +04:00
|
|
|
lea_args_off(args);
|
2011-10-25 21:25:42 +04:00
|
|
|
|
2011-10-27 18:59:21 +04:00
|
|
|
write_string_n(args->core_path);
|
|
|
|
write_string_n(args->self_vmas_path);
|
2011-10-26 22:50:46 +04:00
|
|
|
|
2011-10-26 00:30:41 +04:00
|
|
|
fd_core = sys_open(args->core_path, O_RDONLY, CR_FD_PERM);
|
2011-10-25 23:36:03 +04:00
|
|
|
if (fd_core < 0)
|
2011-10-27 15:34:21 +04:00
|
|
|
goto core_restore_end;
|
2011-10-25 23:36:03 +04:00
|
|
|
|
|
|
|
sys_lseek(fd_core, MAGIC_OFFSET, SEEK_SET);
|
|
|
|
ret = sys_read(fd_core, &core_entry, sizeof(core_entry));
|
|
|
|
if (ret != sizeof(core_entry))
|
2011-10-27 15:34:21 +04:00
|
|
|
goto core_restore_end;
|
2011-10-25 23:36:03 +04:00
|
|
|
|
2011-10-27 18:59:21 +04:00
|
|
|
fd_self_vmas = sys_open(args->self_vmas_path, O_RDONLY, CR_FD_PERM);
|
|
|
|
if (fd_self_vmas < 0)
|
|
|
|
goto core_restore_end;
|
|
|
|
|
|
|
|
write_hex_n(__LINE__);
|
|
|
|
|
|
|
|
/* Note no magic constant on fd_self_vmas */
|
|
|
|
sys_lseek(fd_self_vmas, 0, SEEK_SET);
|
|
|
|
while (1) {
|
|
|
|
ret = sys_read(fd_self_vmas, &vma_entry, sizeof(vma_entry));
|
|
|
|
if (!ret)
|
|
|
|
break;
|
|
|
|
if (ret != sizeof(vma_entry))
|
|
|
|
goto core_restore_end;
|
|
|
|
|
|
|
|
write_hex_n(__LINE__);
|
|
|
|
|
2011-10-27 19:09:33 +04:00
|
|
|
if (!(vma_entry.status & VMA_AREA_REGULAR))
|
|
|
|
continue;
|
|
|
|
|
2011-10-27 18:59:21 +04:00
|
|
|
write_hex_n(vma_entry.start);
|
|
|
|
if (sys_munmap((void *)vma_entry.start,
|
|
|
|
vma_entry.end - vma_entry.start))
|
|
|
|
goto core_restore_end;
|
|
|
|
|
|
|
|
write_hex_n(__LINE__);
|
|
|
|
}
|
|
|
|
|
|
|
|
sys_close(fd_self_vmas);
|
2011-10-27 19:09:33 +04:00
|
|
|
|
2011-10-24 23:56:36 +04:00
|
|
|
/*
|
2011-10-27 19:39:08 +04:00
|
|
|
* OK, lets try to map new one.
|
2011-10-24 23:56:36 +04:00
|
|
|
*/
|
2011-10-27 19:39:08 +04:00
|
|
|
sys_lseek(fd_core, GET_FILE_OFF_AFTER(struct core_entry), SEEK_SET);
|
|
|
|
while (1) {
|
|
|
|
ret = sys_read(fd_core, &vma_entry, sizeof(vma_entry));
|
|
|
|
if (!ret)
|
|
|
|
break;
|
|
|
|
if (ret != sizeof(vma_entry))
|
|
|
|
goto core_restore_end;
|
2011-10-24 23:56:36 +04:00
|
|
|
|
2011-10-27 19:39:08 +04:00
|
|
|
if (!vma_entry.start)
|
|
|
|
break;
|
2011-10-24 23:56:36 +04:00
|
|
|
|
2011-10-27 19:39:08 +04:00
|
|
|
write_hex_n(__LINE__);
|
|
|
|
|
|
|
|
if (!(vma_entry.status & VMA_AREA_REGULAR))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
write_hex_n(vma_entry.start);
|
|
|
|
|
|
|
|
vma_entry.fd = 0; /* for a while */
|
|
|
|
|
|
|
|
/* Should map memory here */
|
|
|
|
va = sys_mmap((void *)vma_entry.start,
|
|
|
|
vma_entry.end - vma_entry.start,
|
|
|
|
vma_entry.prot,
|
|
|
|
vma_entry.flags | MAP_FIXED,
|
|
|
|
vma_entry.fd,
|
|
|
|
vma_entry.pgoff);
|
|
|
|
if (va != vma_entry.start) {
|
|
|
|
write_hex_n(va);
|
|
|
|
goto core_restore_end;
|
|
|
|
}
|
|
|
|
|
|
|
|
write_hex_n(__LINE__);
|
|
|
|
}
|
2011-10-24 23:56:36 +04:00
|
|
|
|
|
|
|
/*
|
2011-10-27 19:39:08 +04:00
|
|
|
* Read page contents.
|
2011-10-24 23:56:36 +04:00
|
|
|
*/
|
2011-10-27 19:39:08 +04:00
|
|
|
while (1) {
|
|
|
|
ret = sys_read(fd_core, &va, sizeof(va));
|
|
|
|
if (!ret)
|
|
|
|
break;
|
|
|
|
if (ret != sizeof(va))
|
|
|
|
goto core_restore_end;
|
|
|
|
|
|
|
|
write_hex_n(__LINE__);
|
|
|
|
if (!va)
|
|
|
|
break;
|
|
|
|
|
|
|
|
ret = sys_read(fd_core, (void *)va, PAGE_SIZE);
|
|
|
|
if (ret != PAGE_SIZE)
|
|
|
|
goto core_restore_end;
|
|
|
|
|
|
|
|
write_hex_n(__LINE__);
|
|
|
|
}
|
|
|
|
|
|
|
|
sys_close(fd_core);
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
asm volatile("pause");
|
|
|
|
|
|
|
|
goto core_restore_end;
|
2011-10-24 23:56:36 +04:00
|
|
|
|
|
|
|
/* Finally call for sigreturn */
|
|
|
|
sys_rt_sigreturn();
|
2011-10-27 15:34:21 +04:00
|
|
|
|
|
|
|
core_restore_end:
|
|
|
|
sys_exit(0);
|
2011-10-24 23:56:36 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ret = -1;
|
|
|
|
break;
|
2011-10-24 22:23:06 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2011-10-26 11:16:00 +04:00
|
|
|
|
|
|
|
self_len_start:
|
|
|
|
asm volatile(
|
|
|
|
".align 16 \t\n"
|
|
|
|
"self: \t\n"
|
|
|
|
"leaq self(%%rip), %%rax \t\n"
|
|
|
|
"movq %%rax, %0 \t\n"
|
|
|
|
: "=r"(ret)
|
|
|
|
:
|
|
|
|
: "memory");
|
|
|
|
goto self_len_end;
|
2011-10-24 22:23:06 +04:00
|
|
|
}
|