Commit 523de236 authored by Cyrill Gorcunov's avatar Cyrill Gorcunov

Initial commit

Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@gmail.com>
parents
*.o
*.d
*.img
*.bin
*.elf
*.out
cscope*
tags
TAGS
ifeq ($(strip $(V)),)
E = @echo
Q = @
else
E = @\#
Q =
endif
export E Q
FIND := find
CSCOPE := cscope
TAGS := ctags
RM := rm
LD := ld
HEXDUMP := hexdump
CC := gcc
ECHO := echo
NM := nm
AWK := awk
SH := sh
CFLAGS += -I./include
CFLAGS += -O0 -ggdb3
LIBS += -lrt
# Additional ARCH settings for x86
ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
-e s/arm.*/arm/ -e s/sa110/arm/ \
-e s/s390x/s390/ -e s/parisc64/parisc/ \
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-e s/sh[234].*/sh/ )
uname_M := $(shell uname -m | sed -e s/i.86/i386/)
ifeq ($(uname_M),i386)
ARCH := x86
DEFINES += -DCONFIG_X86_32
endif
ifeq ($(uname_M),x86_64)
ARCH := x86
DEFINES += -DCONFIG_X86_64
endif
DEFINES += -D_FILE_OFFSET_BITS=64
DEFINES += -D_GNU_SOURCE
ifneq ($(WERROR),0)
WARNINGS += -Werror
endif
WARNINGS += -Wall -Wno-unused
CFLAGS += $(WARNINGS) $(DEFINES)
PROGRAM := crtools
TESTEE := testee
TESTEE-TH := testee-threads
TESTEE-STATIC := testee-static
all: $(PROGRAM) $(TESTEE) $(TESTEE-TH) $(TESTEE-STATIC)
OBJS += crtools.o
OBJS += parasite-syscall.o
OBJS += cr-dump.o
OBJS += cr-restore.o
OBJS += cr-show.o
OBJS += util.o
OBJS += rbtree.o
OBJS += elf.o
OBJS-TESTEE += testee.o
OBJS-TESTEE-TH += testee-threads.o
OBJS-BLOB += parasite.o
DEPS := $(patsubst %.o,%.d,$(OBJS))
DEPS-TESTEE := $(patsubst %.o,%.d,$(OBJS-TESTEE))
DEPS-TESTEE-TH := $(patsubst %.o,%.d,$(OBJS-TESTEE-TH))
DEPS-BLOB := $(patsubst %.o,%.d,$(OBJS-BLOB))
SRCS-BLOB += $(patsubst %.o,%.c,$(OBJS-BLOB))
HEAD-BLOB := $(patsubst %.o,%.h,$(OBJS-BLOB))
HEAD-BLOB-GEN := $(patsubst %.o,%-blob.h,$(OBJS-BLOB))
HEAD-BIN := $(patsubst %.o,%.bin,$(OBJS-BLOB))
HEAD-LDS := $(patsubst %.o,%.lds.S,$(OBJS-BLOB))
HEAD-IDS := $(patsubst %.h,%_h__,$(subst -,_,$(HEAD-BLOB)))
$(OBJS-BLOB): $(SRCS-BLOB) $(DEPS-BLOB)
$(E) " CC " $@
$(Q) $(CC) -c $(CFLAGS) -fpic $< -o $@
$(HEAD-BIN): $(OBJS-BLOB) $(HEAD-LDS)
%.bin: %.o
$(E) " GEN " $@
$(Q) $(LD) -T $(patsubst %.bin,%.lds.S,$@) $< -o $@
$(Q) $(LD) -T $(patsubst %.bin,%-elf.lds.S,$@) $< -o $@.o
$(HEAD-BLOB): $(DEPS-BLOB) $(HEAD-BIN)
%-blob.h: %.bin
%.h: %.bin
$(E) " GEN " $@
$(Q) $(SH) gen-offsets.sh \
$(subst -,_,$(patsubst %.h,%,$@))_h__ \
$(subst -,_,$(patsubst %.h,%,$@))_blob_offset__ \
$(subst -,_,$(patsubst %.h,%,$@))_blob \
$(patsubst %.h,%.o,$@) \
$(patsubst %.h,%.bin,$@) > $(patsubst %.h,%-blob.h,$@)
$(OBJS): $(HEAD-BLOB) $(DEPS)
$(OBJS-TESTEE): $(DEPS-TESTEE)
$(OBJS-TESTEE-TH): $(DEPS-TESTEE-TH)
%.o: %.c
$(E) " CC " $@
$(Q) $(CC) -c $(CFLAGS) $< -o $@
$(PROGRAM): $(OBJS)
$(E) " LINK " $@
$(Q) $(CC) $(OBJS) $(LIBS) -o $@
$(TESTEE): $(OBJS-TESTEE)
$(E) " LINK " $@
$(Q) $(CC) $(OBJS-TESTEE) -o $@
$(TESTEE-TH): $(OBJS-TESTEE-TH)
$(E) " LINK " $@
$(Q) $(CC) $(OBJS-TESTEE-TH) -lpthread -o $@
$(TESTEE-STATIC).o: testee-static.c
$(Q) gcc -c -static -I./.include -o testee-static.o testee-static.c
$(TESTEE-STATIC): $(TESTEE-STATIC).o
$(Q) gcc -o testee-static -static testee-static.o
$(DEPS):
$(DEPS-TESTEE):
$(DEPS-TESTEE-TH):
$(DEPS-BLOB):
%.d: %.c
$(Q) $(CC) -M -MT $(patsubst %.d,%.o,$@) $(CFLAGS) $< -o $@
clean:
$(E) " CLEAN"
$(Q) rm -f ./*.o
$(Q) rm -f ./*.d
$(Q) rm -f ./*.img
$(Q) rm -f ./*.elf
$(Q) rm -f ./*.out
$(Q) rm -f ./*.bin
$(Q) rm -f ./tags
$(Q) rm -f ./cscope*
$(Q) rm -f ./$(PROGRAM)
$(Q) rm -f ./$(TESTEE)
$(Q) rm -f ./$(TESTEE-STATIC)
$(Q) rm -f ./$(TESTEE-TH)
$(Q) rm -f ./$(HEAD-BLOB)
$(Q) rm -f ./$(HEAD-BLOB-GEN)
.PHONY: clean
tags:
$(E) " GEN" $@
$(Q) $(RM) -f tags
$(Q) $(FIND) . -name '*.[hcS]' -print | xargs ctags -a
.PHONY: tags
cscope:
$(E) " GEN" $@
$(Q) $(FIND) . -name '*.[hcS]' -print > cscope.files
$(Q) $(CSCOPE) -bkqu
.PHONY: cscope
crtools
=======
An utility to to checkpoint/restore tasks.
Some code is borrowed from
- Linux kernel (http://kernel.org/)
- git (http://git-scm.com/)
- kvm-tools (https://github.com/penberg/linux-kvm.git)
- ptrace-parasite (https://code.google.com/p/ptrace-parasite/)
Many thanks to these projects.
Licensed under GPLv2
This diff is collapsed.
This diff is collapsed.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <limits.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/vfs.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/wait.h>
#include "types.h"
#include "list.h"
#include "compiler.h"
#include "crtools.h"
#include "syscall.h"
#include "util.h"
#include "image.h"
#ifndef CONFIG_X86_64
# error No x86-32 support yet
#endif
#define pr_regs4(s, n1, n2, n3, n4) \
pr_info("%8s: %16lx " \
"%8s: %16lx " \
"%8s: %16lx " \
"%8s: %16lx\n", \
#n1, s.n1, \
#n2, s.n2, \
#n3, s.n3, \
#n4, s.n4)
#define pr_regs3(s, n1, n2, n3) \
pr_info("%8s: %16lx " \
"%8s: %16lx " \
"%8s: %16lx\n", \
#n1, s.n1, \
#n2, s.n2, \
#n3, s.n3)
static char local_buf[PAGE_SIZE];
static LIST_HEAD(pstree_list);
/* FIXME: same as dump -- unify */
static void free_pstree(void)
{
struct pstree_item *item, *p;
list_for_each_entry_safe(item, p, &pstree_list, list) {
xfree(item->children);
xfree(item);
}
INIT_LIST_HEAD(&pstree_list);
}
static void show_regs(struct cr_fdset *cr_fdset)
{
struct user_regs_entry regs;
struct desc_struct tls;
int fd_core, i;
fd_core = cr_fdset->desc[CR_FD_CORE].fd;
if (fd_core < 0)
goto err;
pr_info("\n\t---[GP registers set]---\n");
lseek(fd_core, GET_FILE_OFF(struct core_entry, gpregs), SEEK_SET);
read_ptr_safe(fd_core, &regs, err);
pr_regs4(regs, cs, ip, ds, es);
pr_regs4(regs, ss, sp, fs, gs);
pr_regs4(regs, di, si, dx, cx);
pr_regs4(regs, ax, r8, r9, r10);
pr_regs4(regs, r11, r12, r13, r14);
pr_regs3(regs, r15, bp, bx);
pr_regs4(regs, orig_ax, flags, fs_base, gs_base);
pr_info("\n\t---[TLS area]---\n");
lseek(fd_core, GET_FILE_OFF(struct core_entry, tls_array), SEEK_SET);
for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) {
read_ptr_safe(fd_core, &tls, err);
pr_info("tls[%2i] = %x %x\n", i, tls.a, tls.b);
}
err:
return;
}
static void show_files(struct cr_fdset *cr_fdset)
{
struct fdinfo_entry e;
int fd_files, ret;
pr_info("\n");
pr_info("CR_FD_FDINFO: %s\n", cr_fdset->desc[CR_FD_FDINFO].name);
pr_info("----------------------------------------\n");
fd_files = cr_fdset->desc[CR_FD_FDINFO].fd;
lseek(fd_files, MAGIC_OFFSET, SEEK_SET);
while (1) {
ret = read(fd_files, &e, sizeof(e));
if (!ret)
goto err;
if (ret != sizeof(e)) {
pr_perror("Can't read fdinfo entry");
goto err;
}
if (e.len) {
ret = read(fd_files, local_buf, e.len);
if (ret != e.len) {
pr_perror("Can't read %d bytes\n", e.len);
goto err;
}
local_buf[e.len] = 0;
pr_info("type: %02x len: %02x flags: %4x pos: %8x addr: %16lx --> %s\n",
e.type, e.len, e.flags, e.pos, e.addr, local_buf);
} else
pr_info("type: %02x len: %02x flags: %4x pos: %8x addr: %16lx\n",
e.type, e.len, e.flags, e.pos, e.addr);
}
err:
pr_info("----------------------------------------\n");
}
static void show_pipes(struct cr_fdset *cr_fdset)
{
struct pipe_entry e;
int fd_pipes, ret;
pr_info("\n");
pr_info("CR_FD_PIPES: %s\n", cr_fdset->desc[CR_FD_PIPES].name);
pr_info("----------------------------------------\n");
fd_pipes = cr_fdset->desc[CR_FD_PIPES].fd;
lseek(fd_pipes, MAGIC_OFFSET, SEEK_SET);
while (1) {
ret = read(fd_pipes, &e, sizeof(e));
if (!ret)
goto err;
if (ret != sizeof(e)) {
pr_perror("Can't read pipe entry\n");
goto err;
}
pr_info("fd: %8lx pipeid: %8lx flags: %8lx bytes: %8lx\n",
e.fd, e.pipeid, e.flags, e.bytes);
if (e.bytes)
lseek(fd_pipes, e.bytes, SEEK_CUR);
}
err:
pr_info("----------------------------------------\n");
}
static void show_core(struct cr_fdset *cr_fdset)
{
struct vma_area vma_area = {};
struct vma_entry ve;
int fd_core, ret;
u64 va;
pr_info("\n");
pr_info("CR_FD_CORE: %s\n", cr_fdset->desc[CR_FD_CORE].name);
pr_info("----------------------------------------\n");
fd_core = cr_fdset->desc[CR_FD_CORE].fd;
if (fd_core < 0)
goto out;
show_regs(cr_fdset);
lseek(fd_core, GET_FILE_OFF_AFTER(struct core_entry), SEEK_SET);
/*
* Start with VMA, then pages.
*/
pr_info("\n\t---[VMA areas]---\n");
while (1) {
ret = read(fd_core, &ve, sizeof(ve));
if (!ret)
break;
if (ret != sizeof(ve)) {
pr_perror("Unable to read VMA\n");
goto out;
}
if (is_ending_vma(&ve)) {
pr_info("\n\t---[Pages]---\n");
while (1) {
ret = read(fd_core, &va, sizeof(va));
if (!ret)
goto out;
if (ret != sizeof(va)) {
pr_perror("Unable to read VA\n");
goto out;
}
if (va == 0)
goto out;
pr_info("page va: %16lx\n", va);
lseek(fd_core, PAGE_SIZE, SEEK_CUR);
}
}
/* Simply in a sake of fancy printing */
vma_area.vma = ve;
pr_info_vma(&vma_area);
}
out:
pr_info("----------------------------------------\n");
}
static void show_pstree_from_file(int fd, char *name)
{
int ret;
pr_info("\n");
pr_info("CR_FD_PSTREE: %s\n", name);
pr_info("----------------------------------------\n");
while (1) {
struct pstree_entry e;
unsigned long i;
u32 child_pid;
ret = read(fd, &e, sizeof(e));
if (!ret)
break;
if (ret != sizeof(e)) {
pr_perror("Bad pstree entry");
break;
}
pr_info("Process %d number of children: %d\n",
e.pid, e.nr_children);
for (i = 0; i < e.nr_children; i++) {
ret = read(fd, &child_pid,
sizeof(child_pid));
pr_info(" %d", child_pid);
}
if (e.nr_children)
pr_info("\n");
}
pr_info("----------------------------------------\n");
}
static void show_pstree(struct list_head *head, char *name)
{
struct pstree_item *item;
int i;
pr_info("\n");
pr_info("CR_FD_PSTREE: %s\n", name);
pr_info("----------------------------------------\n");
list_for_each_entry(item, head, list) {
pr_info("Process %d number of children: %d\n",
item->pid, item->nr_children);
for (i = 0; i < item->nr_children; i++)
pr_info(" %d", item->children[i]);
if (item->nr_children)
pr_info("\n");
}
pr_info("----------------------------------------\n");
}
static int collect_pstree(pid_t pid, struct cr_fdset *cr_fdset)
{
int fd = cr_fdset->desc[CR_FD_PSTREE].fd;
struct pstree_item *item = NULL;
struct pstree_entry e;
int ret = -1;
for (;;) {
size_t size;
ret = read(fd, &e, sizeof(e));
if (ret && ret != sizeof(e)) {
pr_perror("Wrong pstree entry\n");
goto err;
}
if (!ret)
break;
item = xmalloc(sizeof(*item));
if (!item)
goto err;
size = sizeof(u32) * e.nr_children;
item->pid = e.pid;
item->nr_children = e.nr_children;
item->children = xmalloc(size);
if (!item->children) {
pr_error("No memory for children pids\n");
goto err;
}
ret = read(fd, item->children, size);
if (ret != size) {
pr_error("An error in reading children pids\n");
xfree(item->children);
goto err;
}
list_add_tail(&item->list, &pstree_list);
}
item = NULL;
ret = 0;
err:
xfree(item);
return ret;
}
int cr_show(unsigned long pid, bool leader_only)
{
struct cr_fdset *cr_fdset;
struct pstree_item *item;
int i, ret = -1;
cr_fdset = alloc_cr_fdset(pid);
if (!cr_fdset)
goto out;
ret = prep_cr_fdset_for_restore(cr_fdset, CR_FD_DESC_ALL);
if (ret)
goto out;
ret = collect_pstree(pid, cr_fdset);
if (ret)
goto out;
show_pstree(&pstree_list, cr_fdset->desc[CR_FD_PSTREE].name);
close_cr_fdset(cr_fdset);
free_cr_fdset(&cr_fdset);
list_for_each_entry(item, &pstree_list, list) {
cr_fdset = alloc_cr_fdset(item->pid);
if (!cr_fdset)
goto out;
ret = prep_cr_fdset_for_restore(cr_fdset, CR_FD_DESC_NOPSTREE);
if (ret)
goto out;
show_core(cr_fdset);
show_pipes(cr_fdset);
show_files(cr_fdset);
if (leader_only)
break;
}
out:
free_pstree();
close_cr_fdset(cr_fdset);
free_cr_fdset(&cr_fdset);
return ret;
}
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <limits.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/vfs.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <sys/sendfile.h>
#include "types.h"
#include "list.h"
#include "compiler.h"
#include "crtools.h"
#include "util.h"
struct page_entry zero_page_entry;
static struct cr_fd_desc_tmpl template[CR_FD_MAX] = {
[CR_FD_FDINFO] = {
.fmt = "fdinfo-%li.img",
.magic = FDINFO_MAGIC,
},
[CR_FD_PAGES] = {
.fmt = "pages-%li.img",
.magic = PAGES_MAGIC,
},
[CR_FD_PAGES_SHMEM] = {
.fmt = "pages-shmem-%li.img",
.magic = PAGES_MAGIC,
},
[CR_FD_CORE] = {
.fmt = "core-%li.img",
.magic = CORE_MAGIC,
},
[CR_FD_PIPES] = {
.fmt = "pipes-%li.img",
.magic = PIPES_MAGIC,
},
[CR_FD_PSTREE] = {
.fmt = "pstree-%li.img",
.magic = PSTREE_MAGIC,
},
[CR_FD_SHMEM] = {
.fmt = "shmem-%li.img",
.magic = SHMEM_MAGIC,
},
};
struct cr_fdset *alloc_cr_fdset(pid_t pid)
{
struct cr_fdset *cr_fdset;
unsigned int i;
cr_fdset = xzalloc(sizeof(*cr_fdset));
if (!cr_fdset)
goto err;
for (i = 0; i < CR_FD_MAX; i++) {
cr_fdset->desc[i].tmpl = &template[i];
snprintf(cr_fdset->desc[i].name,
sizeof(cr_fdset->desc[i].name),
cr_fdset->desc[i].tmpl->fmt,
(long)pid);
cr_fdset->desc[i].fd = -1;
}
err:
return cr_fdset;
}
int prep_cr_fdset_for_dump(struct cr_fdset *cr_fdset,
unsigned long use_mask)
{
unsigned int i;
u32 magic;
int ret = -1;
if (!cr_fdset)
goto err;
cr_fdset->use_mask = use_mask;
for (i = 0; i < CR_FD_MAX; i++) {
if (!(use_mask & CR_FD_DESC_USE(i)))
continue;
ret = unlink(cr_fdset->desc[i].name);
if (ret && errno != ENOENT) {
pr_perror("Unable to unlink %s (%s)\n",
cr_fdset->desc[i].name,
strerror(errno));
goto err;
} else
ret = -1;
cr_fdset->desc[i].fd = open(cr_fdset->desc[i].name,
O_RDWR | O_CREAT | O_EXCL,
CR_FD_PERM);
if (cr_fdset->desc[i].fd < 0) {
pr_perror("Unable to open %s (%s)\n",
cr_fdset->desc[i].name,
strerror(errno));
goto err;
}
pr_debug("Opened %s with %d\n",
cr_fdset->desc[i].name,
cr_fdset->desc[i].fd);
magic = cr_fdset->desc[i].tmpl->magic;
write_ptr_safe(cr_fdset->desc[i].fd, &magic, err);
/*
* Make sure it's on disk since we might
* need to re-open files in parasite.
*/
fsync(cr_fdset->desc[i].fd);
}
ret = 0;
err:
return ret;
}
int prep_cr_fdset_for_restore(struct cr_fdset *cr_fdset,
unsigned long use_mask)
{
unsigned int i;
int ret = -1;
u32 magic;
if (!cr_fdset)
goto err;
cr_fdset->use_mask = use_mask;
for (i = 0; i < CR_FD_MAX; i++) {
if (!(use_mask & CR_FD_DESC_USE(i)))
continue;
cr_fdset->desc[i].fd = open(cr_fdset->desc[i].name,
O_RDWR, CR_FD_PERM);
if (cr_fdset->desc[i].fd < 0) {
pr_perror("Unable to open %s (%s)\n",
cr_fdset->desc[i].name,
strerror(errno));
goto err;
}
pr_debug("Opened %s with %d\n",
cr_fdset->desc[i].name,
cr_fdset->desc[i].fd);
read_ptr_safe(cr_fdset->desc[i].fd, &magic, err);
if (magic != cr_fdset->desc[i].tmpl->magic) {
pr_error("Magic doesn't match for %s\n",
cr_fdset->desc[i].name);
goto err;
}
}
ret = 0;
err:
return ret;
}
void close_cr_fdset(struct cr_fdset *cr_fdset)
{
unsigned int i;
if (!cr_fdset)
return;
for (i = 0; i < CR_FD_MAX; i++) {
if (!(cr_fdset->use_mask & CR_FD_DESC_USE(i)))
continue;
if (cr_fdset->desc[i].fd >= 0) {
pr_debug("Closed %s with %d\n",
cr_fdset->desc[i].name,
cr_fdset->desc[i].fd);
close(cr_fdset->desc[i].fd);
cr_fdset->desc[i].fd = -1;
}
}
}
void free_cr_fdset(struct cr_fdset **cr_fdset)
{
if (cr_fdset && *cr_fdset) {
free(*cr_fdset);
*cr_fdset = NULL;
}
}
int main(int argc, char *argv[])
{
pid_t pid;
int ret = -1;
BUILD_BUG_ON(PAGE_SIZE != PAGE_IMAGE_SIZE);
if (argc < 3)
goto usage;
memset(&zero_page_entry, 0, sizeof(zero_page_entry));
if (!strcmp(argv[1], "dump")) {
bool leader_only;
switch (argv[2][1]) {
case 'p':
pid = atol(argv[3]);
leader_only = true;
break;
case 't':
pid = atol(argv[3]);
leader_only = false;
break;
default:
goto usage;
}
ret = cr_dump_tasks(pid, leader_only, 1);
} else if (!strcmp(argv[1], "restore")) {
bool leader_only;
switch (argv[2][1]) {
case 'p':
pid = atol(argv[3]);
leader_only = true;
break;
case 't':
pid = atol(argv[3]);
leader_only = false;
break;
default:
goto usage;
}
ret = cr_restore_tasks(pid, leader_only, 1);
} else if (!strcmp(argv[1], "show")) {
bool leader_only = true;
switch (argv[2][1]) {
case 'p':
leader_only = true;
pid = atol(argv[3]);
break;
case 't':
leader_only = false;
pid = atol(argv[3]);
break;
default:
goto usage;
}
ret = cr_show(pid, leader_only);
} else
goto usage;
return ret;
usage:
printk("\nUsage:\n");
printk("\tcrtools (dump|show|restore) (-p|-t) pid\n\n");
return -1;
}
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <limits.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/vfs.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <sys/sendfile.h>
#include "types.h"
#include "list.h"
#include "compiler.h"
#include "crtools.h"
#include "syscall.h"
#include "util.h"
#include "image.h"
#include "elf.h"
#define ELF_MAX_PHDR ((65536U / sizeof(Elf64_Phdr)) - 1)
#define ELF_MAX_PAGES (1 << 10)
/*
* Convert the c/r core file into elf
* executable, the kernel will handle it.
*/
int convert_to_elf(char *elf_path, int fd_core)
{
Elf64_Ehdr elf_ehdr;
Elf64_Phdr elf_phdr;
Elf64_Half e_phnum = 0;
Elf64_Addr e_entry = 0;
struct page_entry page_entry;
unsigned long nrpages = 0;
struct core_entry core;
struct vma_area area;
struct vma_entry vma;
u64 va;
unsigned long phoff = 0;
unsigned long phoff_regs, phoff_pages;
int fd_elf;
int ret = -1;
fd_elf = open(elf_path, O_RDWR | O_CREAT | O_EXCL, 0700);
if (fd_elf < 0) {
pr_perror("Can't open %s\n", elf_path);
goto err;
}
memset(&elf_ehdr, 0, sizeof(elf_ehdr));
memset(&area, 0, sizeof(area));
memcpy(elf_ehdr.e_ident, ELFMAG, SELFMAG);
elf_ehdr.e_ident[EI_CLASS] = ELFCLASS64;
elf_ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
elf_ehdr.e_ident[EI_VERSION] = EV_CURRENT;
elf_ehdr.e_type = ET_CKPT;
elf_ehdr.e_machine = EM_X86_64;
elf_ehdr.e_version = EV_CURRENT;
elf_ehdr.e_phoff = sizeof(elf_ehdr);
elf_ehdr.e_ehsize = sizeof(elf_ehdr);
elf_ehdr.e_phentsize = sizeof(Elf64_Phdr);
/* Get EP */
lseek(fd_core, MAGIC_OFFSET, SEEK_SET);
read_ptr_safe(fd_core, &core, err_close);
/*
* Count the numbers of segments. Each segment
* is the VMA record with appropriate permissions.
* Then we need one big segment which would hold
* all the pages dumped.
*/
lseek(fd_core, GET_FILE_OFF_AFTER(struct core_entry), SEEK_SET);
while(1) {
read_ptr_safe(fd_core, &vma, err_close);
if (vma.start == 0 && vma.end == 0)
break;
e_phnum++;
}
while (1) {
read_ptr_safe(fd_core, &va, err_close);
nrpages++;
if (va == 0)
break;
lseek(fd_core, PAGE_SIZE, SEEK_CUR);
}
/* Figure out if we're overflowed */
if (e_phnum > ELF_MAX_PHDR) {
pr_error("Too many VMA areas (%li of %li allowed)\n",
e_phnum, ELF_MAX_PHDR);
goto err_close;
} else if (nrpages > ELF_MAX_PAGES) {
pr_error("Too many pages to restore (%li of %li allowed)\n",
nrpages, ELF_MAX_PAGES);
goto err_close;
}
/*
* We can write elf header now.
*/
lseek(fd_elf, 0, SEEK_SET);
elf_ehdr.e_phnum = e_phnum + 2;
elf_ehdr.e_entry = core.gpregs.ip;
write_ptr_safe(fd_elf, &elf_ehdr, err_close);
/* Offset in file (after all headers) */
phoff = elf_ehdr.e_phnum * sizeof(elf_phdr) + sizeof(elf_ehdr);
/* VMAs to headers */
e_phnum = 0;
lseek(fd_core, GET_FILE_OFF_AFTER(struct core_entry), SEEK_SET);
while(1) {
read_ptr_safe(fd_core, &vma, err_close);
if (vma.start == 0 && vma.end == 0)
break;
memset(&elf_phdr, 0, sizeof(elf_phdr));
elf_phdr.p_type = PT_CKPT_VMA;
elf_phdr.p_offset = phoff;
elf_phdr.p_vaddr = vma.start;
elf_phdr.p_paddr = vma.start;
elf_phdr.p_filesz = sizeof(vma);
elf_phdr.p_memsz = vma.end - vma.start;
elf_phdr.p_align = 0x1000;
if (vma.prot & PROT_READ)
elf_phdr.p_flags |= PF_R;
if (vma.prot & PROT_WRITE)
elf_phdr.p_flags |= PF_W;
if (vma.prot & PROT_EXEC)
elf_phdr.p_flags |= PF_X;
write_ptr_safe(fd_elf, &elf_phdr, err_close);
phoff += sizeof(vma);
}
/* The binfmt header */
memset(&elf_phdr, 0, sizeof(elf_phdr));
elf_phdr.p_type = PT_CKPT_CORE;
elf_phdr.p_flags = PF_R;
elf_phdr.p_offset = phoff;
elf_phdr.p_vaddr = 0;
elf_phdr.p_filesz = sizeof(core);
elf_phdr.p_memsz = sizeof(core);
elf_phdr.p_align = 0x1000;
write_ptr_safe(fd_elf, &elf_phdr, err_close);
phoff += sizeof(core);
/* The pages and binfmt header */
memset(&elf_phdr, 0, sizeof(elf_phdr));
elf_phdr.p_type = PT_CKPT_PAGES;
elf_phdr.p_flags = PF_R;
elf_phdr.p_offset = phoff;
elf_phdr.p_vaddr = 0;
elf_phdr.p_filesz = nrpages * (sizeof(page_entry));
elf_phdr.p_memsz = nrpages * (sizeof(page_entry));
elf_phdr.p_align = 0x1000;
write_ptr_safe(fd_elf, &elf_phdr, err_close);
/* Now write real contents for program segments */
lseek(fd_core, GET_FILE_OFF_AFTER(struct core_entry), SEEK_SET);
while(1) {
read_ptr_safe(fd_core, &vma, err_close);
if (vma.start == 0 && vma.end == 0)
break;
area.vma = vma, pr_info_vma(&area);
write_ptr_safe(fd_elf, &vma, err_close);
}
write_ptr_safe(fd_elf, &core, err_close);
if (sendfile(fd_elf, fd_core, NULL, nrpages * (sizeof(page_entry))) !=
nrpages * (sizeof(page_entry))) {
pr_perror("Can't send %li bytes to elf\n",
(long)(nrpages * (sizeof(page_entry))));
goto err;
}
ret = 0;
err_close:
close(fd_elf);
err:
return ret;
}
#!/bin/sh
name_ifndef=$1
name_prefix_offset=$2
name_blob=$3
name_objname=$4
name_bin=$5
awk_cmd="{ print \"#define $name_prefix_offset\" \$3 \" 0x\" \$1; }"
echo "/* Autogenerated file, don't edit */"
echo "#ifndef $name_ifndef"
echo "#define $name_ifndef"
echo ""
nm $name_objname | grep ' [Tt] ' | awk "$awk_cmd"
echo ""
echo "static char $name_blob[] = {"
hexdump -v -e '"\t"' -e '8/1 "0x%02x, "' -e '"\n"' $name_bin
echo "};"
echo ""
echo "#endif /* $name_ifndef */"
#ifndef CR_BITOPS_H_
#define CR_BITOPS_H_
#ifdef CONFIG_X86_64
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, 8 * sizeof(long))
#define DECLARE_BITMAP(name, bits) \
unsigned long name[BITS_TO_LONGS(bits)]
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1)
/* Technically wrong, but this avoids compilation errors on some gcc
versions. */
#define BITOP_ADDR(x) "=m" (*(volatile long *) (x))
#else
#define BITOP_ADDR(x) "+m" (*(volatile long *) (x))
#endif
#define ADDR BITOP_ADDR(addr)
static void set_bit(int nr, volatile unsigned long *addr)
{
asm volatile("bts %1,%0" : ADDR : "Ir" (nr) : "memory");
}
static void change_bit(int nr, volatile unsigned long *addr)
{
asm volatile("btc %1,%0" : ADDR : "Ir" (nr));
}
static int test_bit(int nr, volatile const unsigned long *addr)
{
int oldbit;
asm volatile("bt %2,%1\n\t"
"sbb %0,%0"
: "=r" (oldbit)
: "m" (*(unsigned long *)addr), "Ir" (nr));
return oldbit;
}
static void clear_bit(int nr, volatile unsigned long *addr)
{
asm volatile("btr %1,%0" : ADDR : "Ir" (nr));
}
#else /* CONFIG_X86_64 */
# error x86-32 is not implemented yet
#endif /* CONFIG_X86_64 */
#endif /* CR_BITOPS_H_ */
#ifndef CR_COMPILER_H_
#define CR_COMPILER_H_
/*
* Various definitions for success build,
* picked from various places, mostly from
* the linux kernel.
*/
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)
#define NORETURN __attribute__((__noreturn__))
#define __packed __attribute__((__packed__))
#define __used __attribute__((__used__))
#define __section(S) __attribute__ ((__section__(#S)))
#ifndef __always_inline
# define __always_inline inline __attribute__((always_inline))
#endif
#ifndef always_inline
# define always_inline __always_inline
#endif
#ifndef offsetof
# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define __round_mask(x, y) ((__typeof__(x))((y) - 1))
#define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1)
#define round_down(x, y) ((x) & ~__round_mask(x, y))
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; })
#define max(x, y) ({ \
typeof(x) _max1 = (x); \
typeof(y) _max2 = (y); \
(void) (&_max1 == &_max2); \
_max1 > _max2 ? _max1 : _max2; })
#define is_log2(v) (((v) & ((v) - 1)) == 0)
#endif /* CR_COMPILER_H_ */
#ifndef CRTOOLS_H_
#define CRTOOLS_H_
#include <sys/types.h>
#include "types.h"
#include "list.h"
#include "image.h"
extern struct page_entry zero_page_entry;
int cr_dump_tasks(pid_t pid, bool leader_only, int leave_stopped);
int cr_restore_tasks(pid_t pid, bool leader_only, int leave_stopped);
int cr_show(unsigned long pid, bool leader_only);
int convert_to_elf(char *elf_path, int fd_core);
#define CR_FD_PERM 0600
enum {
CR_FD_FDINFO,
CR_FD_PAGES,
CR_FD_PAGES_SHMEM,
CR_FD_CORE,
CR_FD_PIPES,
CR_FD_PSTREE,
CR_FD_SHMEM,
CR_FD_MAX
};
/* file descriptors template */
struct cr_fd_desc_tmpl {
const char *fmt; /* format for the name */
u32 magic; /* magic in the header */
};
/* file descriptors */
struct cr_fd_desc {
struct cr_fd_desc_tmpl *tmpl; /* template we refer to */
char name[64]; /* the name, based on pid */
int fd; /* descriptor for open/close */
};
struct cr_fdset {
struct cr_fd_desc desc[CR_FD_MAX];
u32 use_mask; /*
* if descriptor get used,set
* bit here
*/
};
#define CR_FD_DESC_USE(type) ((1 << (type)))
#define CR_FD_DESC_ALL ((1 << CR_FD_MAX) - 1)
#define CR_FD_DESC_NOPSTREE (CR_FD_DESC_ALL & ~(CR_FD_DESC_USE(CR_FD_PSTREE)))
#define CR_FD_DESC_NONE (0)
struct cr_fdset *alloc_cr_fdset(pid_t pid);
int prep_cr_fdset_for_dump(struct cr_fdset *cr_fdset,
unsigned long use_mask);
int prep_cr_fdset_for_restore(struct cr_fdset *cr_fdset,
unsigned long use_mask);
void close_cr_fdset(struct cr_fdset *cr_fdset);
void free_cr_fdset(struct cr_fdset **cr_fdset);
struct vma_area {
struct list_head list;
struct vma_entry vma;
unsigned long shmid;
int vm_file_fd;
};
#define vma_area_has(vma_area, s) vma_entry_has(&vma_area->vma, s)
#define vma_entry_len(vma) ((vma)->end - (vma)->start)
struct pstree_item {
struct list_head list;
pid_t pid; /* leader pid */
u32 nr_children; /* number of children */
u32 *children; /* array of children */
};
struct pstree_item_info {
struct list_head list;
pid_t pid; /* leader pid */
u32 nr_children; /* number of children */
u32 *children; /* array of children */
bool launched; /* set if launched */
};
static inline unsigned long vma_area_size(struct vma_area *vma)
{
return vma->vma.end - vma->vma.start;
}
static inline int in_vma_area(struct vma_area *vma, unsigned long addr)
{
return addr >= (unsigned long)vma->vma.start &&
addr < (unsigned long)vma->vma.end;
}
#endif /* CRTOOLS_H_ */
This diff is collapsed.
#ifndef CR_IMAGE_H
#define CR_IMAGE_H
#include "types.h"
#include "compiler.h"
#define FDINFO_MAGIC 0x01010101
#define PAGES_MAGIC 0x20202020
#define CORE_MAGIC 0xa75b8d43
#define SHMEM_MAGIC 0x03300330
#define PIPEFS_MAGIC 0x50495045
#define PSTREE_MAGIC 0x40044004
#define PIPES_MAGIC 0x05055050
#define FDINFO_FD 1
#define FDINFO_MAP 2
#define PAGE_IMAGE_SIZE 4096
#define PAGE_RSS 1
struct fdinfo_entry {
u8 type;
u8 len;
u16 flags;
u32 pos;
u64 addr;
u8 name[0];
} __packed;
struct shmem_entry {
u64 start;
u64 end;
u64 shmid;
} __packed;
struct pstree_entry {
u32 pid;
u32 nr_children;
u32 children[0];
} __packed;
struct pipe_entry {
u32 fd;
u32 pipeid;
u32 flags;
u32 bytes;
u8 data[0];
} __packed;
#define VMA_AREA_REGULAR (1 << 0)
#define VMA_AREA_STACK (1 << 1)
#define VMA_AREA_VSYSCALL (1 << 2)
#define VMA_AREA_VDSO (1 << 3)
#define VMA_FORCE_READ (1 << 4)
#define VMA_AREA_HEAP (1 << 5)
#define VMA_FILE_PRIVATE (1 << 6)
#define VMA_FILE_SHARED (1 << 7)
#define VMA_ANON_SHARED (1 << 8)
#define VMA_ANON_PRIVATE (1 << 9)
#define VMA_FORCE_WRITE (1 << 10)
#define VMA_DUMP_ALL (1 << 11)
#define vma_entry_has(vma, s) (((vma)->status & (s)) == (s))
struct vma_entry {
u64 start;
u64 end;
u64 pgoff;
u32 prot;
u32 flags;
u32 status;
u32 pid;
s64 fd;
u64 ino;
u32 dev_maj;
u32 dev_min;
} __packed;
struct page_entry {
u64 va;
u8 data[PAGE_IMAGE_SIZE];
} __packed;
#define HEADER_VERSION 1
#define HEADER_ARCH_X86_64 1
struct image_header {
u16 version;
u16 arch;
u32 flags;
} __packed;
/*
* PTRACE_GETREGS
* PTRACE_GETFPREGS
* PTRACE_GETFPXREGS dep CONFIG_X86_32
* PTRACE_GET_THREAD_AREA dep CONFIG_X86_32 || CONFIG_IA32_EMULATION
* PTRACE_GETFDPIC dep CONFIG_BINFMT_ELF_FDPIC
*
* PTRACE_ARCH_PRCTL dep CONFIG_X86_64
* ARCH_SET_GS/ARCH_GET_FS
* ARCH_SET_FS/ARCH_GET_GS
*/
#ifdef CONFIG_X86_64
struct user_regs_entry {
u64 r15;
u64 r14;
u64 r13;
u64 r12;
u64 bp;
u64 bx;
u64 r11;
u64 r10;
u64 r9;
u64 r8;
u64 ax;
u64 cx;
u64 dx;
u64 si;
u64 di;
u64 orig_ax;
u64 ip;
u64 cs;
u64 flags;
u64 sp;
u64 ss;
u64 fs_base;
u64 gs_base;
u64 ds;
u64 es;
u64 fs;
u64 gs;
} __packed;
struct desc_struct {
union {
struct {
u32 a;
u32 b;
};
struct {
u16 limit0;
u16 base0;
unsigned base1: 8, type: 4, s: 1, dpl: 2, p: 1;
unsigned limit: 4, avl: 1, l: 1, d: 1, g: 1, base2: 8;
};
};
} __packed;
struct user_fpregs_entry {
u16 cwd;
u16 swd;
u16 twd; /* Note this is not the same as
the 32bit/x87/FSAVE twd */
u16 fop;
u64 rip;
u64 rdp;
u32 mxcsr;
u32 mxcsr_mask;
u32 st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */
u32 padding[24];
} __packed;
#define GDT_ENTRY_TLS_ENTRIES 3
struct core_entry {
struct image_header hdr;
struct user_regs_entry gpregs;
struct user_fpregs_entry fpregs;
struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
u32 personality;
} __packed;
#endif /* CONFIG_X86_64 */
#ifndef offsetof
# define offsetof(TYPE, MEMBER) ((long) &((TYPE *)0)->MEMBER)
#endif
/*
* There are always 4 magic bytes at the
* beginning of the every file.
*/
#define MAGIC_OFFSET (sizeof(u32))
#define GET_FILE_OFF(s, m) (offsetof(s,m) + MAGIC_OFFSET)
#define GET_FILE_OFF_AFTER(s) (sizeof(s) + MAGIC_OFFSET)
#endif /* CR_IMAGE_H */
#ifndef CR_LIST_H_
#define CR_LIST_H_
/*
* Double linked lists.
*/
#include "compiler.h"
#define POISON_POINTER_DELTA 0
#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)
#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA)
struct list_head {
struct list_head *prev, *next;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
static inline void __list_del_entry(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
static inline void list_replace(struct list_head *old,
struct list_head *new)
{
new->next = old->next;
new->next->prev = new;
new->prev = old->prev;
new->prev->next = new;
}
static inline void list_replace_init(struct list_head *old,
struct list_head *new)
{
list_replace(old, new);
INIT_LIST_HEAD(old);
}
static inline void list_del_init(struct list_head *entry)
{
__list_del_entry(entry);
INIT_LIST_HEAD(entry);
}
static inline void list_move(struct list_head *list, struct list_head *head)
{
__list_del_entry(list);
list_add(list, head);
}
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del_entry(list);
list_add_tail(list, head);
}
static inline int list_is_last(const struct list_head *list,
const struct list_head *head)
{
return list->next == head;
}
static inline int list_is_first(const struct list_head *list,
const struct list_head *head)
{
return list->prev == head;
}
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
static inline int list_empty_careful(const struct list_head *head)
{
struct list_head *next = head->next;
return (next == head) && (next == head->prev);
}
static inline void list_rotate_left(struct list_head *head)
{
struct list_head *first;
if (!list_empty(head)) {
first = head->next;
list_move_tail(first, head);
}
}
static inline int list_is_singular(const struct list_head *head)
{
return !list_empty(head) && (head->next == head->prev);
}
static inline void __list_cut_position(struct list_head *list,
struct list_head *head, struct list_head *entry)
{
struct list_head *new_first = entry->next;
list->next = head->next;
list->next->prev = list;
list->prev = entry;
entry->next = list;
head->next = new_first;
new_first->prev = head;
}
static inline void list_cut_position(struct list_head *list,
struct list_head *head, struct list_head *entry)
{
if (list_empty(head))
return;
if (list_is_singular(head) &&
(head->next != entry && head != entry))
return;
if (entry == head)
INIT_LIST_HEAD(list);
else
__list_cut_position(list, head, entry);
}
static inline void __list_splice(const struct list_head *list,
struct list_head *prev,
struct list_head *next)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
first->prev = prev;
prev->next = first;
last->next = next;
next->prev = last;
}
static inline void list_splice(const struct list_head *list,
struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head, head->next);
}
static inline void list_splice_tail(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head->prev, head);
}
static inline void list_splice_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head, head->next);
INIT_LIST_HEAD(list);
}
}
static inline void list_splice_tail_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head->prev, head);
INIT_LIST_HEAD(list);
}
}
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define __list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; pos != (head); pos = pos->prev)
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
#define list_for_each_prev_safe(pos, n, head) \
for (pos = (head)->prev, n = pos->prev; \
pos != (head); \
pos = n, n = pos->prev)
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_reverse(pos, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))
#define list_prepare_entry(pos, head, member) \
((pos) ? : list_entry(head, typeof(*pos), member))
#define list_for_each_entry_continue(pos, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_continue_reverse(pos, head, member) \
for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))
#define list_for_each_entry_from(pos, head, member) \
for (; &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#define list_for_each_entry_safe_continue(pos, n, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#define list_for_each_entry_safe_from(pos, n, head, member) \
for (n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member), \
n = list_entry(pos->member.prev, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.prev, typeof(*n), member))
#define list_safe_reset_next(pos, n, member) \
n = list_entry(pos->member.next, typeof(*pos), member)
#endif /* CR_LIST_H_ */
#ifndef PARASITE_SYSCALL_H_
#define PARASITE_SYSCALL_H_
#include <sys/types.h>
#include <sys/mman.h>
#include "compiler.h"
#include "types.h"
#include "list.h"
#include "crtools.h"
#define BUILTIN_SYSCALL_SIZE 8
/* parasite control block */
struct parasite_ctl {
pid_t pid; /* process where we live */
struct vma_area *vma_area; /* our space */
unsigned long parasite_ip; /* service routine start ip */
unsigned long parasite_complete_ip; /* where we end execution */
unsigned long addr_cmd; /* addr for command */
unsigned long addr_args; /* address for arguments */
};
int can_run_syscall(unsigned long ip, unsigned long start, unsigned long end);
void *mmap_seized(pid_t pid, user_regs_struct_t *regs,
void *addr, size_t length, int prot,
int flags, int fd, off_t offset);
int munmap_seized(pid_t pid, user_regs_struct_t *regs,
void *addr, size_t length);
int kill_seized(pid_t pid, user_regs_struct_t *where);
int syscall_seized(pid_t pid,
user_regs_struct_t *where,
user_regs_struct_t *params,
user_regs_struct_t *result);
int parasite_dump_pages_seized(struct parasite_ctl *ctl, struct list_head *vma_area_list,
struct cr_fdset *cr_fdset, int fd_type);
struct parasite_ctl *parasite_infect_seized(pid_t pid, void *addr_hint, struct list_head *vma_area_list);
int parasite_cure_seized(struct parasite_ctl **p_ctrl, struct list_head *vma_area_list);
#endif /* PARASITE_SYSCALL_H_ */
#ifndef CR_PARASITE_H_
#define CR_PARASITE_H_
#include "compiler.h"
#include "syscall.h"
#include "image.h"
#define __parasite_head __used __section(.parasite.head.text)
#define __parasite_text __used __section(.parasite.text)
#define __parasite_stack __used __section(.parasite.stack)
#define PARASITE_STACK_SIZE 2048
#define PARASITE_ARG_SIZE 256
#define PARASITE_BRK_SIZE 32768
#define PARASITE_MAX_SIZE (64 << 10)
/* we need own error code for diagnostics */
#define PARASITE_ERR_FAIL -1024
#define PARASITE_ERR_OPEN -1025
#define PARASITE_ERR_MMAP -1026
#define PARASITE_ERR_MINCORE -1027
#define PARASITE_ERR_MUNMAP -1028
#define PARASITE_ERR_CLOSE -1029
#define PARASITE_ERR_WRITE -1030
#define PARASITE_ERR_MPROTECT -1031
#define PARASITE_ERR_CORE_VMA -1032
#define PARASITE_ERR_CORE_PAGE -1033
enum {
PARASITE_CMD_NONE,
PARASITE_CMD_KILLME,
PARASITE_CMD_PINGME,
PARASITE_CMD_DUMPPAGES,
PARASITE_CMD_RESTORECORE,
PARASITE_CMD_MAX,
};
typedef struct {
unsigned long command;
unsigned long args_size;
void *args;
} parasite_args_t;
typedef struct {
struct vma_entry vma_entry;
unsigned long nrpages_dumped; /* how many pages are dumped */
unsigned long fd;
unsigned long open_mode;
unsigned long open_flags;
char open_path[64];
} parasite_args_cmd_dumppages_t;
/*
* Some useful offsets
*/
#define PARASITE_ARGS_ADDR(start) \
((start) + parasite_blob_offset__parasite_args)
#define PARASITE_CMD_ADDR(start) \
((start) + parasite_blob_offset__parasite_cmd)
#define PARASITE_HEAD_ADDR(start) \
((start) + parasite_blob_offset__parasite_head_start)
#define PARASITE_COMPLETE_ADDR(start) \
((start) + parasite_blob_offset__parasite_service_complete)
#endif /* CR_PARASITE_H_ */
/*
* RBtree implementation adopted from the Linux
* kernel sources.
*/
#ifndef _LINUX_RBTREE_H
#define _LINUX_RBTREE_H
#include <stddef.h>
#define RB_RED 0
#define RB_BLACK 1
#define RB_COLOR_MASK 3
struct rb_node {
unsigned long rb_parent_color;
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));
struct rb_root {
struct rb_node *rb_node;
};
#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~RB_COLOR_MASK))
#define rb_color(r) ((r)->rb_parent_color & RB_BLACK)
#define rb_is_red(r) (!rb_color(r))
#define rb_is_black(r) rb_color(r)
#define rb_set_red(r) do { (r)->rb_parent_color &= ~RB_BLACK; } while (0)
#define rb_set_black(r) do { (r)->rb_parent_color |= RB_BLACK; } while (0)
static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
{
rb->rb_parent_color = (rb->rb_parent_color & RB_COLOR_MASK) |(unsigned long)p;
}
static inline void rb_set_color(struct rb_node *rb, int color)
{
rb->rb_parent_color = (rb->rb_parent_color & ~RB_BLACK) | color;
}
#define RB_ROOT (struct rb_root) { NULL, }
#define rb_entry(ptr, type, member) \
container_of(ptr, type, member)
#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
static inline void rb_init_node(struct rb_node *rb)
{
rb->rb_parent_color = 0;
rb->rb_right = NULL;
rb->rb_left = NULL;
RB_CLEAR_NODE(rb);
}
void rb_insert_color(struct rb_node *, struct rb_root *);
void rb_erase(struct rb_node *, struct rb_root *);
struct rb_node *rb_next(const struct rb_node *node);
struct rb_node *rb_prev(const struct rb_node *node);
struct rb_node *rb_first(const struct rb_root *node);
struct rb_node *rb_last(const struct rb_root *node);
void rb_replace_node(struct rb_node *victim, struct rb_node *new,
struct rb_root *root);
static inline void rb_link_node(struct rb_node *node, struct rb_node *parent,
struct rb_node **rb_link)
{
node->rb_parent_color = (unsigned long )parent;
node->rb_left = node->rb_right = NULL;
*rb_link = node;
}
#endif /* _LINUX_RBTREE_H */
#ifndef CR_SYSCALL_H_
#define CR_SYSCALL_H_
#include <sys/types.h>
#include "compiler.h"
#ifdef CONFIG_X86_64
static long syscall0(int nr)
{
long ret;
asm volatile("syscall"
: "=a" (ret)
: "a" (nr)
: "memory");
return ret;
}
static long syscall1(int nr, unsigned long arg0)
{
long ret;
asm volatile("syscall"
: "=a" (ret)
: "a" (nr), "D" (arg0)
: "memory");
return ret;
}
static long syscall2(int nr, unsigned long arg0, unsigned long arg1)
{
long ret;
asm volatile("syscall"
: "=a" (ret)
: "a" (nr), "D" (arg0), "S" (arg1)
: "memory");
return ret;
}
static long syscall3(int nr, unsigned long arg0, unsigned long arg1,
unsigned long arg2)
{
long ret;
asm volatile("syscall"
: "=a" (ret)
: "a" (nr), "D" (arg0), "S" (arg1), "d" (arg2)
: "memory");
return ret;
}
static long syscall4(int nr, unsigned long arg0, unsigned long arg1,
unsigned long arg2, unsigned long arg3)
{
register unsigned long r10 asm("r10") = r10;
long ret;
r10 = arg3;
asm volatile("syscall"
: "=a" (ret)
: "a" (nr), "D" (arg0), "S" (arg1), "d" (arg2)
: "memory");
return ret;
}
static long syscall5(int nr, unsigned long arg0, unsigned long arg1,
unsigned long arg2, unsigned long arg3,
unsigned long arg4)
{
register unsigned long r10 asm("r10") = r10;
register unsigned long r8 asm("r8") = r8;
long ret;
r10 = arg3;
r8 = arg4;
asm volatile("syscall"
: "=a" (ret)
: "a" (nr), "D" (arg0), "S" (arg1), "d" (arg2)
: "memory");
return ret;
}
static long syscall6(int nr, unsigned long arg0, unsigned long arg1,
unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
register unsigned long r10 asm("r10") = r10;
register unsigned long r8 asm("r8") = r8;
register unsigned long r9 asm("r9") = r9;
long ret;
r10 = arg3;
r8 = arg4;
r9 = arg5;
asm volatile("syscall"
: "=a" (ret)
: "a" (nr), "D" (arg0), "S" (arg1), "d" (arg2)
: "memory");
return ret;
}
/*
* syscall codes
*/
#define __NR_read 0
#define __NR_write 1
#define __NR_open 2
#define __NR_close 3
#define __NR_lseek 8
#define __NR_mmap 9
#define __NR_mprotect 10
#define __NR_munmap 11
#define __NR_mincore 27
#define __NR_dup 32
#define __NR_dup2 33
#define __NR_pause 34
#define __NR_nanosleep 35
#define __NR_getpid 39
#define __NR_exit 60
static unsigned long sys_pause(void)
{
return syscall0(__NR_pause);
}
static unsigned long sys_mmap(void *addr, unsigned long len, unsigned long prot,
unsigned long flags, unsigned long fd, unsigned long offset)
{
return syscall6(__NR_mmap, (unsigned long)addr,
len, prot, flags, fd, offset);
}
static unsigned long sys_munmap(void *addr,unsigned long len)
{
return syscall2(__NR_munmap, (unsigned long)addr, len);
}
static long sys_open(const char *filename, unsigned long flags, unsigned long mode)
{
return syscall3(__NR_open, (unsigned long)filename, flags, mode);
}
static long sys_close(int fd)
{
return syscall1(__NR_close, fd);
}
static long sys_write(unsigned long fd, const void *buf, unsigned long count)
{
return syscall3(__NR_write, fd, (unsigned long)buf, count);
}
static long sys_mincore(unsigned long addr, unsigned long size, void *vec)
{
return syscall3(__NR_mincore, addr, size, (unsigned long)vec);
}
static long sys_lseek(unsigned long fd, unsigned long offset, unsigned long origin)
{
return syscall3(__NR_lseek, fd, offset, origin);
}
static long sys_mprotect(unsigned long start, unsigned long len, unsigned long prot)
{
return syscall3(__NR_mprotect, start, len, prot);
}
static long sys_nanosleep(struct timespec *req, struct timespec *rem)
{
return syscall2(__NR_nanosleep, (unsigned long)req, (unsigned long)rem);
}
static long sys_read(unsigned long fd, void *buf, unsigned long count)
{
return syscall3(__NR_read, fd, (unsigned long)buf, count);
}
#else /* CONFIG_X86_64 */
# error x86-32 bit mode not yet implemented
#endif /* CONFIG_X86_64 */
#endif /* CR_SYSCALL_H_ */
#ifndef CR_TYPES_H_
#define CR_TYPES_H_
#include <stdint.h>
#include <stdbool.h>
#include "bitops.h"
/* some constants for ptrace */
#define PTRACE_SEIZE 0x4206
#define PTRACE_INTERRUPT 0x4207
#define PTRACE_LISTEN 0x4208
#define PTRACE_SEIZE_DEVEL 0x80000000
#define PTRACE_EVENT_FORK 1
#define PTRACE_EVENT_VFORK 2
#define PTRACE_EVENT_CLONE 3
#define PTRACE_EVENT_EXEC 4
#define PTRACE_EVENT_VFORK_DONE 5
#define PTRACE_EVENT_EXIT 6
#define PTRACE_EVENT_STOP 7
#define PTRACE_O_TRACESYSGOOD 0x00000001
#define PTRACE_O_TRACEFORK 0x00000002
#define PTRACE_O_TRACEVFORK 0x00000004
#define PTRACE_O_TRACECLONE 0x00000008
#define PTRACE_O_TRACEEXEC 0x00000010
#define PTRACE_O_TRACEVFORKDONE 0x00000020
#define PTRACE_O_TRACEEXIT 0x00000040
/* fcntl */
#ifndef F_LINUX_SPECIFIC_BASE
#define F_LINUX_SPECIFIC_BASE 1024
#endif
#ifndef F_SETPIPE_SZ
# define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
#endif
#ifndef F_GETPIPE_SZ
# define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8)
#endif
#define CLONE_CHILD_USEPID 0x02000000
#define CLONE_VFORK 0x00004000
typedef uint64_t u64;
typedef int64_t s64;
typedef unsigned int u32;
typedef signed int s32;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned char u8;
typedef signed char s8;
#define MAJOR(dev) ((dev)>>8)
#ifdef CONFIG_X86_64
typedef struct {
unsigned long r15;
unsigned long r14;
unsigned long r13;
unsigned long r12;
unsigned long bp;
unsigned long bx;
unsigned long r11;
unsigned long r10;
unsigned long r9;
unsigned long r8;
unsigned long ax;
unsigned long cx;
unsigned long dx;
unsigned long si;
unsigned long di;
unsigned long orig_ax;
unsigned long ip;
unsigned long cs;
unsigned long flags;
unsigned long sp;
unsigned long ss;
unsigned long fs_base;
unsigned long gs_base;
unsigned long ds;
unsigned long es;
unsigned long fs;
unsigned long gs;
} user_regs_struct_t;
typedef struct {
unsigned short cwd;
unsigned short swd;
unsigned short twd; /* Note this is not the same as
the 32bit/x87/FSAVE twd */
unsigned short fop;
u64 rip;
u64 rdp;
u32 mxcsr;
u32 mxcsr_mask;
u32 st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */
u32 padding[24];
} user_fpregs_struct_t;
#else /* CONFIG_X86_64 */
typedef struct {
unsigned long bx;
unsigned long cx;
unsigned long dx;
unsigned long si;
unsigned long di;
unsigned long bp;
unsigned long ax;
unsigned long ds;
unsigned long es;
unsigned long fs;
unsigned long gs;
unsigned long orig_ax;
unsigned long ip;
unsigned long cs;
unsigned long flags;
unsigned long sp;
unsigned long ss;
} user_regs_struct_t;
#endif /* CONFIG_X86_64 */
#ifndef PAGE_SIZE
# define PAGE_SIZE 4096
#endif
#endif /* CR_TYPES_H_ */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
proc: Introduce the Children: line in /proc/<pid>/status
From: Pavel Emelyanov <xemul@parallels.com>
Although we can get the pids of some task's issue, this is just
more convenient to have them this way.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
---
fs/proc/array.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
Index: linux-2.6.git/fs/proc/array.c
===================================================================
--- linux-2.6.git.orig/fs/proc/array.c
+++ linux-2.6.git/fs/proc/array.c
@@ -158,6 +158,18 @@ static inline const char *get_task_state
return *p;
}
+static void task_children(struct seq_file *m, struct task_struct *p, struct pid_namespace *ns)
+{
+ struct task_struct *c;
+
+ seq_printf(m, "Children:");
+ read_lock(&tasklist_lock);
+ list_for_each_entry(c, &p->children, sibling)
+ seq_printf(m, " %d", pid_nr_ns(task_pid(c), ns));
+ read_unlock(&tasklist_lock);
+ seq_putc(m, '\n');
+}
+
static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *p)
{
@@ -192,6 +204,8 @@ static inline void task_state(struct seq
cred->uid, cred->euid, cred->suid, cred->fsuid,
cred->gid, cred->egid, cred->sgid, cred->fsgid);
+ task_children(m, p, ns);
+
task_lock(p);
if (p->files)
fdt = files_fdtable(p->files);
This diff is collapsed.
vfs: Add ->statfs callback for pipefs
From: Pavel Emelyanov <xemul@parallels.com>
This is done to make it possible to distinguish pipes
from fifos when opening one via /proc/<pid>/fd/ link.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Reviewed-by: Tejun Heo <tj@kernel.org>
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
---
fs/pipe.c | 1 +
1 file changed, 1 insertion(+)
Index: linux-2.6.git/fs/pipe.c
===================================================================
--- linux-2.6.git.orig/fs/pipe.c
+++ linux-2.6.git/fs/pipe.c
@@ -1254,6 +1254,7 @@ out:
static const struct super_operations pipefs_ops = {
.destroy_inode = free_inode_nonrcu,
+ .statfs = simple_statfs,
};
/*
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment