[CRIU] [PATCH] crit: merge criu-coredump

Ruslan Kuprieiev kupruser at gmail.com
Fri May 6 12:09:36 PDT 2016


It was originally developed as a "crit coredump" action, but it
was decided to move it into a separate project about a year ago.
Several month ago there was a discussion about moving it back to
criu repo, so here is a patch to consider.

It gone through some RFC and fixing to make it work with criu 2.x.

Description from an original set:

This set itroduces a new CRIT feature called "core-dump". The name
is pretty much self-explanatory, it allows generating core dumps
from criu images. Core dumps are readable and usable by gdb.
The structure is something in the middle of kernel-generated
and gdb-generated core dumps.

This is a first iteration of core-dump patch series. It introduces
ability to generate gdb-operatable core dump only for x86_64 machine.
To support other architectures there will be a set to introduce proper
structures for notes section of the core dump. It is also worth noting,
that we still leave some notes(SIGINFO primarily) not fullfilled, as
I still need to figure out what to put in there in our case, where no
signal is involved in triggering core dump generation and other
caveats like zeroed vvar(we have problems with it withing CRIU itself
as well as gdb has some difficalties with it) and vsyscall vmas.
One can already use produced core dump with gdb, there is also
a quick simple demo https://asciinema.org/a/18936 .

Signed-off-by: Ruslan Kuprieiev <kupruser at gmail.com>
---
 crit/crit                   |  30 ++
 lib/py/__init__.py          |   1 +
 lib/py/coredump/.gitignore  |   1 +
 lib/py/coredump/__init__.py |   1 +
 lib/py/coredump/coredump.py | 829 ++++++++++++++++++++++++++++++++++++++++++++
 lib/py/coredump/elf.py      | 526 ++++++++++++++++++++++++++++
 6 files changed, 1388 insertions(+)
 create mode 100644 lib/py/coredump/.gitignore
 create mode 100644 lib/py/coredump/__init__.py
 create mode 100644 lib/py/coredump/coredump.py
 create mode 100644 lib/py/coredump/elf.py

diff --git a/crit/crit b/crit/crit
index 93cbc98..97734b4 100755
--- a/crit/crit
+++ b/crit/crit
@@ -217,6 +217,19 @@ explorers = { 'ps': explore_ps, 'fds': explore_fds, 'mems': explore_mems }
 def explore(opts):
 	explorers[opts['what']](opts)
 
+#
+# Coredump
+#
+def coredump(opts):
+	generator = pycriu.coredump.coredump_generator()
+	cores = generator(os.path.realpath(opts['in']))
+	for pid in cores:
+		if opts['pid'] and pid != opts['pid']:
+			continue
+		with open(os.path.realpath(opts['out'])+"/core."+str(pid), 'w+') as f:
+			cores[pid].write(f)
+
+
 def main():
 	desc = 'CRiu Image Tool'
 	parser = argparse.ArgumentParser(description=desc,
@@ -267,6 +280,23 @@ def main():
 	show_parser.add_argument("in")
 	show_parser.set_defaults(func=decode, pretty=True, out=None)
 
+	# Coredump
+	coredump_parser = subparsers.add_parser('coredump',
+			help = 'generate coredumps from criu images')
+	coredump_parser.add_argument('-i',
+				'--in',
+				default = '.',
+			help = 'directory where to get images from')
+	coredump_parser.add_argument('-p',
+				'--pid',
+				type = int,
+			help = 'generate coredump for specific pid(all pids py default)')
+	coredump_parser.add_argument('-o',
+				'--out',
+				default = '.',
+			help = 'directory to write coredumps to')
+	coredump_parser.set_defaults(func=coredump)
+
 	opts = vars(parser.parse_args())
 
 	opts["func"](opts)
diff --git a/lib/py/__init__.py b/lib/py/__init__.py
index 7de6283..bf9c0a5 100644
--- a/lib/py/__init__.py
+++ b/lib/py/__init__.py
@@ -1,3 +1,4 @@
 import rpc
 import images
+import coredump
 from criu import *
diff --git a/lib/py/coredump/.gitignore b/lib/py/coredump/.gitignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/lib/py/coredump/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/lib/py/coredump/__init__.py b/lib/py/coredump/__init__.py
new file mode 100644
index 0000000..79881f7
--- /dev/null
+++ b/lib/py/coredump/__init__.py
@@ -0,0 +1 @@
+from coredump import *
diff --git a/lib/py/coredump/coredump.py b/lib/py/coredump/coredump.py
new file mode 100644
index 0000000..0bbe309
--- /dev/null
+++ b/lib/py/coredump/coredump.py
@@ -0,0 +1,829 @@
+# Functions and classes for creating core dump from criu images.
+# Code is inspired by outdated google coredumper(RIP) [1] and
+# fs/binfmt_elf.h from Linux kernel [2].
+#
+# [1] https://code.google.com/p/google-coredumper/
+#     probably already dead, so consider trying:
+#     https://github.com/efiop/google-coredumper/
+# [2] https://www.kernel.org/
+#
+# On my x86_64 systems with fresh kernel ~3.17 core dump looks like:
+#
+#	1) Elf file header;
+#	2) PT_NOTE program header describing notes section;
+#	3) PT_LOAD program headers for (almost?) each vma;
+#	4) NT_PRPSINFO note with elf_prpsinfo inside;
+#	5) An array of notes for each thread of the process:
+#		NT_PRSTATUS note with elf_prstatus inside;
+#		NT_FPREGSET note with elf_fpregset inside;
+#		NT_X86_XSTATE note with x86 extended state using xsave;
+#		NT_SIGINFO note with siginfo_t inside;
+#	6) NT_AUXV note with auxv;
+#	7) NT_FILE note with mapped files;
+#	8) VMAs themselves;
+#
+# Or, you can represent it in less details as:
+#	1) Elf file header;
+#	2) Program table;
+#	3) Notes;
+#	4) VMAs contents;
+#
+import io
+import elf
+import ctypes
+from .. import images
+
+# Some memory-related constants
+PAGESIZE = 4096
+status = {
+	"VMA_AREA_NONE"		: 0 << 0,
+	"VMA_AREA_REGULAR"	: 1 << 0,
+	"VMA_AREA_STACK"	: 1 << 1,
+	"VMA_AREA_VSYSCALL"	: 1 << 2,
+	"VMA_AREA_VDSO"		: 1 << 3,
+	"VMA_FORCE_READ"	: 1 << 4,
+	"VMA_AREA_HEAP"		: 1 << 5,
+	"VMA_FILE_PRIVATE"	: 1 << 6,
+	"VMA_FILE_SHARED"	: 1 << 7,
+	"VMA_ANON_SHARED"	: 1 << 8,
+	"VMA_ANON_PRIVATE"	: 1 << 9,
+	"VMA_AREA_SYSVIPC"	: 1 << 10,
+	"VMA_AREA_SOCKET"	: 1 << 11,
+	"VMA_AREA_VVAR"		: 1 << 12,
+	"VMA_AREA_AIORING"	: 1 << 13,
+	"VMA_AREA_UNSUPP"	: 1 << 31
+}
+
+prot = {
+	"PROT_READ"	: 0x1,
+	"PROT_WRITE"	: 0x2,
+	"PROT_EXEC"	: 0x4
+}
+
+class elf_note:
+	nhdr	= None	# Elf_Nhdr;
+	owner	= None	# i.e. CORE or LINUX;
+	data	= None	# Ctypes structure with note data;
+
+
+class coredump:
+	"""
+	A class to keep elf core dump components inside and
+	functions to properly write them to file.
+	"""
+	ehdr	= None	# Elf ehdr;
+	phdrs	= []	# Array of Phdrs;
+	notes	= []	# Array of elf_notes;
+	vmas	= []	# Array of BytesIO with memory content;
+			# FIXME keeping all vmas in memory is a bad idea;
+
+	def write(self, f):
+		"""
+		Write core dump to file f.
+		"""
+		buf = io.BytesIO()
+		buf.write(self.ehdr)
+
+		for phdr in self.phdrs:
+			buf.write(phdr)
+
+		for note in self.notes:
+			buf.write(note.nhdr)
+			buf.write(note.owner)
+			buf.write("\0"*(8-len(note.owner)))
+			buf.write(note.data)
+
+		offset = ctypes.sizeof(elf.Elf64_Ehdr())
+		offset += (len(self.vmas) + 1)*ctypes.sizeof(elf.Elf64_Phdr())
+
+		filesz = 0
+		for note in self.notes:
+			filesz += ctypes.sizeof(note.nhdr) + ctypes.sizeof(note.data) + 8
+
+		note_align	= PAGESIZE - ((offset + filesz) % PAGESIZE)
+
+		if note_align == PAGESIZE:
+			note_align = 0
+
+		if note_align != 0:
+			scratch = (ctypes.c_char * note_align)()
+			ctypes.memset(ctypes.addressof(scratch), 0, ctypes.sizeof(scratch))
+			buf.write(scratch)
+
+		for vma in self.vmas:
+			buf.write(vma.data)
+
+		buf.seek(0)
+		f.write(buf.read())
+
+
+class coredump_generator:
+	"""
+	Generate core dump from criu images.
+	"""
+	coredumps	= {} # coredumps by pid;
+
+	pstree		= {} # process info by pid;
+	cores		= {} # cores by pid;
+	mms		= {} # mm by pid;
+	reg_files	= None # reg-files;
+	pagemaps	= {} # pagemap by pid;
+
+	def _img_open_and_strip(self, name, single = False, pid = None):
+		"""
+		Load criu image and strip it from magic and redundant list.
+		"""
+		path = self._imgs_dir + "/" + name
+		if pid:
+			path += "-"+str(pid)
+		path += ".img"
+
+		with open(path) as f:
+			img = images.load(f)
+
+		if single:
+			return img["entries"][0]
+		else:
+			return img["entries"]
+
+
+	def __call__(self, imgs_dir):
+		"""
+		Parse criu images stored in directory imgs_dir to fill core dumps.
+		"""
+		self._imgs_dir	= imgs_dir
+		pstree		= self._img_open_and_strip("pstree")
+
+		for p in pstree:
+			pid = p['pid']
+
+			self.pstree[pid]	= p
+			for tid in p['threads']:
+				self.cores[tid]	= self._img_open_and_strip("core", True, tid)
+			self.mms[pid]		= self._img_open_and_strip("mm", True, pid)
+			self.pagemaps[pid]	= self._img_open_and_strip("pagemap", False, pid)
+
+		self.reg_files	= self._img_open_and_strip("reg-files", False)
+
+		for pid in self.pstree:
+			self.coredumps[pid] = self._gen_coredump(pid)
+
+		return self.coredumps
+
+
+	def write(self, coredumps_dir, pid = None):
+		"""
+		Write core dumpt to cores_dir directory. Specify pid to choose
+		core dump of only one process.
+		"""
+		for p in self.coredumps:
+			if pid and p != pid:
+				continue
+			with open(coredumps_dir+"/"+"core."+str(p), 'w+') as f:
+				self.coredumps[p].write(f)
+
+	def _gen_coredump(self, pid):
+		"""
+		Generate core dump for pid.
+		"""
+		cd = coredump()
+
+		# Generate everything backwards so it is easier to calculate offset.
+		cd.vmas		= self._gen_vmas(pid)
+		cd.notes	= self._gen_notes(pid)
+		cd.phdrs	= self._gen_phdrs(pid, cd.notes, cd.vmas)
+		cd.ehdr		= self._gen_ehdr(pid, cd.phdrs)
+
+		return cd
+
+	def _gen_ehdr(self, pid, phdrs):
+		"""
+		Generate elf header for process pid with program headers phdrs.
+		"""
+		ehdr = elf.Elf64_Ehdr()
+
+		ctypes.memset(ctypes.addressof(ehdr), 0, ctypes.sizeof(ehdr))
+		ehdr.e_ident[elf.EI_MAG0]	= elf.ELFMAG0
+		ehdr.e_ident[elf.EI_MAG1]	= elf.ELFMAG1
+		ehdr.e_ident[elf.EI_MAG2]	= elf.ELFMAG2
+		ehdr.e_ident[elf.EI_MAG3]	= elf.ELFMAG3
+		ehdr.e_ident[elf.EI_CLASS]	= elf.ELFCLASS64
+		ehdr.e_ident[elf.EI_DATA]	= elf.ELFDATA2LSB
+		ehdr.e_ident[elf.EI_VERSION]	= elf.EV_CURRENT
+
+		ehdr.e_type		= elf.ET_CORE
+		ehdr.e_machine		= elf.EM_X86_64
+		ehdr.e_version		= elf.EV_CURRENT
+		ehdr.e_phoff		= ctypes.sizeof(elf.Elf64_Ehdr())
+		ehdr.e_ehsize		= ctypes.sizeof(elf.Elf64_Ehdr())
+		ehdr.e_phentsize	= ctypes.sizeof(elf.Elf64_Phdr())
+		#FIXME Case len(phdrs) > PN_XNUM should be handled properly.
+		# See fs/binfmt_elf.c from linux kernel.
+		ehdr.e_phnum	= len(phdrs)
+
+		return ehdr
+
+	def _gen_phdrs(self, pid, notes, vmas):
+		"""
+		Generate program headers for process pid.
+		"""
+		phdrs = []
+
+		offset = ctypes.sizeof(elf.Elf64_Ehdr())
+		offset += (len(vmas) + 1)*ctypes.sizeof(elf.Elf64_Phdr())
+
+		filesz = 0
+		for note in notes:
+			filesz += ctypes.sizeof(note.nhdr) + ctypes.sizeof(note.data) + 8
+
+		# PT_NOTE
+		phdr = elf.Elf64_Phdr()
+		ctypes.memset(ctypes.addressof(phdr), 0, ctypes.sizeof(phdr))
+		phdr.p_type	= elf.PT_NOTE
+		phdr.p_offset	= offset
+		phdr.p_filesz	= filesz
+
+		phdrs.append(phdr)
+
+		note_align	= PAGESIZE - ((offset + filesz) % PAGESIZE)
+
+		if note_align == PAGESIZE:
+			note_align = 0
+
+		offset += note_align
+
+		# VMA phdrs
+
+		for vma in vmas:
+			offset += filesz
+			filesz = vma.filesz
+			phdr = elf.Elf64_Phdr()
+			ctypes.memset(ctypes.addressof(phdr), 0, ctypes.sizeof(phdr))
+			phdr.p_type	= elf.PT_LOAD
+			phdr.p_align	= PAGESIZE
+			phdr.p_paddr	= 0
+			phdr.p_offset	= offset
+			phdr.p_vaddr	= vma.start
+			phdr.p_memsz	= vma.memsz
+			phdr.p_filesz	= vma.filesz
+			phdr.p_flags	= vma.flags
+
+			phdrs.append(phdr)
+
+		return phdrs
+
+	def _gen_prpsinfo(self, pid):
+		"""
+		Generate NT_PRPSINFO note for process pid.
+		"""
+		pstree	= self.pstree[pid]
+		core	= self.cores[pid]
+
+		prpsinfo = elf.elf_prpsinfo()
+		ctypes.memset(ctypes.addressof(prpsinfo), 0, ctypes.sizeof(prpsinfo))
+
+		# FIXME TASK_ALIVE means that it is either running or sleeping, need to
+		# teach criu to distinguish them.
+		TASK_ALIVE	= 0x1
+		# XXX A bit of confusion here, as in ps "dead" and "zombie"
+		# state are two separate states, and we use TASK_DEAD for zombies.
+		TASK_DEAD	= 0x2
+		TASK_STOPPED	= 0x3
+		if core["tc"]["task_state"] == TASK_ALIVE:
+			prpsinfo.pr_state	= 0
+		if core["tc"]["task_state"] == TASK_DEAD:
+			prpsinfo.pr_state	= 4
+		if core["tc"]["task_state"] == TASK_STOPPED:
+			prpsinfo.pr_state	= 3
+		# Don't even ask me why it is so, just borrowed from linux
+		# source and made pr_state match.
+		prpsinfo.pr_sname	= '.' if prpsinfo.pr_state > 5 else "RSDTZW"[prpsinfo.pr_state]
+		prpsinfo.pr_zomb	= 1 if prpsinfo.pr_state == 4 else 0
+		prpsinfo.pr_nice	= core["thread_core"]["sched_prio"] if "sched_prio" in core["thread_core"] else 0
+		prpsinfo.pr_flag	= core["tc"]["flags"]
+		prpsinfo.pr_uid		= core["thread_core"]["creds"]["uid"]
+		prpsinfo.pr_gid		= core["thread_core"]["creds"]["gid"]
+		prpsinfo.pr_pid		= pid
+		prpsinfo.pr_ppid	= pstree["ppid"]
+		prpsinfo.pr_pgrp	= pstree["pgid"]
+		prpsinfo.pr_sid		= pstree["sid"]
+		prpsinfo.pr_fname	= core["tc"]["comm"]
+		prpsinfo.pr_psargs	= self._gen_cmdline(pid)
+
+		nhdr = elf.Elf64_Nhdr()
+		nhdr.n_namesz	= 5
+		nhdr.n_descsz	= ctypes.sizeof(elf.elf_prpsinfo())
+		nhdr.n_type	= elf.NT_PRPSINFO
+
+		note = elf_note()
+		note.data	= prpsinfo
+		note.owner	= "CORE"
+		note.nhdr 	= nhdr
+
+		return note
+
+	def _gen_prstatus(self, pid, tid):
+		"""
+		Generate NT_PRSTATUS note for thread tid of process pid.
+		"""
+		core	= self.cores[tid]
+		regs	= core["thread_info"]["gpregs"]
+		pstree	= self.pstree[pid]
+
+		prstatus = elf.elf_prstatus()
+
+		ctypes.memset(ctypes.addressof(prstatus), 0, ctypes.sizeof(prstatus))
+
+		#FIXME setting only some of the fields for now. Revisit later.
+		prstatus.pr_pid		= tid
+		prstatus.pr_ppid	= pstree["ppid"]
+		prstatus.pr_pgrp	= pstree["pgid"]
+		prstatus.pr_sid		= pstree["sid"]
+
+		prstatus.pr_reg.r15		= regs["r15"]
+		prstatus.pr_reg.r14		= regs["r14"]
+		prstatus.pr_reg.r13		= regs["r13"]
+		prstatus.pr_reg.r12		= regs["r12"]
+		prstatus.pr_reg.rbp		= regs["bp"]
+		prstatus.pr_reg.rbx		= regs["bx"]
+		prstatus.pr_reg.r11		= regs["r11"]
+		prstatus.pr_reg.r10		= regs["r10"]
+		prstatus.pr_reg.r9		= regs["r9"]
+		prstatus.pr_reg.r8		= regs["r8"]
+		prstatus.pr_reg.rax		= regs["ax"]
+		prstatus.pr_reg.rcx		= regs["cx"]
+		prstatus.pr_reg.rdx		= regs["dx"]
+		prstatus.pr_reg.rsi		= regs["si"]
+		prstatus.pr_reg.rdi		= regs["di"]
+		prstatus.pr_reg.orig_rax	= regs["orig_ax"]
+		prstatus.pr_reg.rip		= regs["ip"]
+		prstatus.pr_reg.cs		= regs["cs"]
+		prstatus.pr_reg.eflags		= regs["flags"]
+		prstatus.pr_reg.rsp		= regs["sp"]
+		prstatus.pr_reg.ss		= regs["ss"]
+		prstatus.pr_reg.fs_base		= regs["fs_base"]
+		prstatus.pr_reg.gs_base		= regs["gs_base"]
+		prstatus.pr_reg.ds		= regs["ds"]
+		prstatus.pr_reg.es		= regs["es"]
+		prstatus.pr_reg.fs		= regs["fs"]
+		prstatus.pr_reg.gs		= regs["gs"]
+
+		nhdr = elf.Elf64_Nhdr()
+		nhdr.n_namesz	= 5
+		nhdr.n_descsz	= ctypes.sizeof(elf.elf_prstatus())
+		nhdr.n_type	= elf.NT_PRSTATUS
+
+		note = elf_note()
+		note.data	= prstatus
+		note.owner	= "CORE"
+		note.nhdr 	= nhdr
+
+		return note
+
+	def _gen_fpregset(self, pid, tid):
+		"""
+		Generate NT_FPREGSET note for thread tid of process pid.
+		"""
+		core	= self.cores[tid]
+		regs	= core["thread_info"]["fpregs"]
+
+		fpregset = elf.elf_fpregset_t()
+		ctypes.memset(ctypes.addressof(fpregset), 0, ctypes.sizeof(fpregset))
+
+		fpregset.cwd		= regs["cwd"]
+		fpregset.swd		= regs["swd"]
+		fpregset.ftw		= regs["twd"]
+		fpregset.fop		= regs["fop"]
+		fpregset.rip		= regs["rip"]
+		fpregset.rdp		= regs["rdp"]
+		fpregset.mxcsr		= regs["mxcsr"]
+		fpregset.mxcr_mask	= regs["mxcsr_mask"]
+		fpregset.st_space	= (ctypes.c_uint * len(regs["st_space"]))(*regs["st_space"])
+		fpregset.xmm_space	= (ctypes.c_uint * len(regs["xmm_space"]))(*regs["xmm_space"])
+		#fpregset.padding	= regs["padding"] unused
+
+		nhdr = elf.Elf64_Nhdr()
+		nhdr.n_namesz	= 5
+		nhdr.n_descsz	= ctypes.sizeof(elf.elf_fpregset_t())
+		nhdr.n_type	= elf.NT_FPREGSET
+
+		note = elf_note()
+		note.data	= fpregset
+		note.owner	= "CORE"
+		note.nhdr 	= nhdr
+
+		return note
+
+	def _gen_x86_xstate(self, pid, tid):
+		"""
+		Generate NT_X86_XSTATE note for thread tid of process pid.
+		"""
+		core	= self.cores[tid]
+		fpregs	= core["thread_info"]["fpregs"]
+
+		data = elf.elf_xsave_struct()
+		ctypes.memset(ctypes.addressof(data), 0, ctypes.sizeof(data))
+
+		data.i387.cwd		= fpregs["cwd"]
+		data.i387.swd		= fpregs["swd"]
+		data.i387.twd		= fpregs["twd"]
+		data.i387.fop		= fpregs["fop"]
+		data.i387.rip		= fpregs["rip"]
+		data.i387.rdp		= fpregs["rdp"]
+		data.i387.mxcsr		= fpregs["mxcsr"]
+		data.i387.mxcsr_mask	= fpregs["mxcsr_mask"]
+		data.i387.st_space	= (ctypes.c_uint * len(fpregs["st_space"]))(*fpregs["st_space"])
+		data.i387.xmm_space	= (ctypes.c_uint * len(fpregs["xmm_space"]))(*fpregs["xmm_space"])
+
+		if "xsave" in fpregs:
+			data.xsave_hdr.xstate_bv = fpregs["xsave"]["xstate_bv"]
+			data.ymmh.ymmh_space	= (ctypes.c_uint * len(fpregs["xsave"]["ymmh_space"]))(*fpregs["xsave"]["ymmh_space"])
+
+		nhdr = elf.Elf64_Nhdr()
+		nhdr.n_namesz	= 6
+		nhdr.n_descsz	= ctypes.sizeof(data)
+		nhdr.n_type	= elf.NT_X86_XSTATE
+
+		note = elf_note()
+		note.data	= data
+		note.owner	= "LINUX"
+		note.nhdr 	= nhdr
+
+		return note
+
+	def _gen_siginfo(self, pid, tid):
+		"""
+		Generate NT_SIGINFO note for thread tid of process pid.
+		"""
+		siginfo = elf.siginfo_t()
+		# FIXME zeroify everything for now
+		ctypes.memset(ctypes.addressof(siginfo), 0, ctypes.sizeof(siginfo))
+
+		nhdr = elf.Elf64_Nhdr()
+		nhdr.n_namesz	= 5
+		nhdr.n_descsz	= ctypes.sizeof(elf.siginfo_t())
+		nhdr.n_type	= elf.NT_SIGINFO
+
+		note = elf_note()
+		note.data	= siginfo
+		note.owner	= "CORE"
+		note.nhdr 	= nhdr
+
+		return note
+
+	def _gen_auxv(self, pid):
+		"""
+		Generate NT_AUXV note for thread tid of process pid.
+		"""
+		mm = self.mms[pid]
+		num_auxv = len(mm["mm_saved_auxv"])/2
+
+		class elf_auxv(ctypes.Structure):
+			_fields_ = [("auxv", elf.Elf64_auxv_t*num_auxv)]
+
+		auxv = elf_auxv()
+		for i in range(num_auxv):
+			auxv.auxv[i].a_type	= mm["mm_saved_auxv"][i]
+			auxv.auxv[i].a_val	= mm["mm_saved_auxv"][i+1]
+
+		nhdr = elf.Elf64_Nhdr()
+		nhdr.n_namesz	= 5
+		nhdr.n_descsz	= ctypes.sizeof(elf_auxv())
+		nhdr.n_type	= elf.NT_AUXV
+
+		note = elf_note()
+		note.data	= auxv
+		note.owner	= "CORE"
+		note.nhdr	= nhdr
+
+		return note
+
+	def _gen_files(self, pid):
+		"""
+		Generate NT_FILE note for process pid.
+		"""
+		mm = self.mms[pid]
+
+		class mmaped_file_info:
+			start		= None
+			end		= None
+			file_ofs	= None
+			name		= None
+
+		infos = []
+		for vma in mm["vmas"]:
+			if vma["shmid"] == 0:
+				# shmid == 0 means that it is not a file
+				continue
+
+			shmid	= vma["shmid"]
+			size	= vma["end"] - vma["start"]
+			off	= vma["pgoff"]/PAGESIZE
+
+			files	= self.reg_files
+			fname	= filter(lambda x: x["id"] == shmid, files)[0]["name"]
+
+			info = mmaped_file_info()
+			info.start	= vma["start"]
+			info.end	= vma["end"]
+			info.file_ofs	= off
+			info.name	= fname
+
+			infos.append(info)
+
+		# /*
+		#  * Format of NT_FILE note:
+		#  *
+		#  * long count     -- how many files are mapped
+		#  * long page_size -- units for file_ofs
+		#  * array of [COUNT] elements of
+		#  *   long start
+		#  *   long end
+		#  *   long file_ofs
+		#  * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL...
+		#  */
+		fields = []
+		fields.append(("count",		ctypes.c_long))
+		fields.append(("page_size",	ctypes.c_long))
+		for i in range(len(infos)):
+			fields.append(("start"+str(i),		ctypes.c_long))
+			fields.append(("end"+str(i),		ctypes.c_long))
+			fields.append(("file_ofs"+str(i),	ctypes.c_long))
+		for i in range(len(infos)):
+			fields.append(("name"+str(i),	ctypes.c_char*(len(infos[i].name)+1)))
+
+		class elf_files(ctypes.Structure):
+			_fields_ = fields
+
+		data = elf_files()
+		data.count	= len(infos)
+		data.page_size	= PAGESIZE
+		for i in range(len(infos)):
+			info = infos[i]
+			setattr(data,	"start"+str(i),		info.start)
+			setattr(data,	"end"+str(i),		info.end)
+			setattr(data,	"file_ofs"+str(i),	info.file_ofs)
+			setattr(data,	"name"+str(i),		info.name)
+
+		nhdr = elf.Elf64_Nhdr()
+
+		nhdr.n_namesz	= 5#XXX strlen + 1
+		nhdr.n_descsz	= ctypes.sizeof(elf_files())
+		nhdr.n_type	= elf.NT_FILE
+
+		note = elf_note()
+		note.nhdr	= nhdr
+		note.owner	= "CORE"
+		note.data	= data
+
+		return note
+
+	def _gen_thread_notes(self, pid, tid):
+		notes = []
+
+		notes.append(self._gen_prstatus(pid, tid))
+		notes.append(self._gen_fpregset(pid, tid))
+		notes.append(self._gen_x86_xstate(pid, tid))
+		notes.append(self._gen_siginfo(pid, tid))
+
+		return notes
+
+	def _gen_notes(self, pid):
+		"""
+		Generate notes for core dump of process pid.
+		"""
+		notes = []
+
+		notes.append(self._gen_prpsinfo(pid))
+
+		threads = self.pstree[pid]["threads"]
+
+		# Main thread first
+		notes += self._gen_thread_notes(pid, pid)
+
+		# Then other threads
+		for tid in threads:
+			if tid == pid:
+				continue
+
+			notes += self._gen_thread_notes(pid, tid)
+
+		notes.append(self._gen_auxv(pid))
+		notes.append(self._gen_files(pid))
+
+		return notes
+
+	def _get_page(self, pid, page_no):
+		"""
+		Try to find memory page page_no in pages.img image for process pid.
+		"""
+		pagemap = self.pagemaps[pid]
+
+		# First entry is pagemap_head, we will need it later to open
+		# proper pages.img.
+		pages_id = pagemap[0]["pages_id"]
+		off = 0# in pages
+		for m in pagemap[1:]:
+			found = False
+			for i in xrange(m["nr_pages"]):
+				if m["vaddr"] + i*PAGESIZE == page_no*PAGESIZE:
+					found = True
+					break
+				off += 1
+
+			if not found:
+				continue
+
+			if "in_parent" in m and m["in_parent"] == True:
+				ppid = self.pstree[pid]["ppid"]
+				return self._get_page(ppid, page_no)
+			else:
+				with open(self._imgs_dir+"/"+"pages-"+str(pages_id)+".img") as f:
+					f.seek(off*PAGESIZE)
+					return f.read(PAGESIZE)
+
+		return None
+
+	def _gen_mem_chunk(self, pid, vma, size):
+		"""
+		Obtain vma contents for process pid.
+		"""
+		f = None
+
+		if size == 0:
+			return ""
+
+		if vma["status"] & status["VMA_AREA_VVAR"]:
+			#FIXME this is what gdb does, as vvar vma
+			# is not readable from userspace?
+			return "\0"*size
+		elif vma["status"] & status["VMA_AREA_VSYSCALL"]:
+			#FIXME need to dump it with criu or read from
+			# current process.
+			return "\0"*size
+
+		if vma["status"] & status["VMA_FILE_SHARED"] or \
+		   vma["status"] & status["VMA_FILE_PRIVATE"]:
+			# Open file before iterating vma pages
+			shmid	= vma["shmid"]
+			off	= vma["pgoff"]
+
+			files	= self.reg_files
+			fname	= filter(lambda x: x["id"] == shmid, files)[0]["name"]
+
+			f = open(fname)
+			f.seek(off)
+
+		start	= vma["start"]
+		end	= vma["start"] + size
+
+		# Split requested memory chunk into pages, so it could be
+		# pictured as:
+		#
+		# "----" -- part of page with memory outside of our vma;
+		# "XXXX" -- memory from our vma;
+		#
+		#  Start page     Pages in the middle        End page
+		# [-----XXXXX]...[XXXXXXXXXX][XXXXXXXXXX]...[XXX-------]
+		#
+		# Each page could be found in pages.img or in a standalone
+		# file described by shmid field in vma entry and
+		# corresponding entry in reg-files.img.
+		# For VMA_FILE_PRIVATE vma, unchanged pages are taken from
+		# a file, and changed ones -- from pages.img.
+		# Finally, if no page is found neither in pages.img nor
+		# in file, hole in inserted -- a page filled with zeroes.
+		start_page	= start/PAGESIZE
+		end_page	= end/PAGESIZE
+
+		buf = ""
+		for page_no in range(start_page, end_page+1):
+			page = None
+
+			# Search for needed page in pages.img and reg-files.img
+			# and choose appropriate.
+			page_mem = self._get_page(pid, page_no)
+
+			if f != None:
+				page = f.read(PAGESIZE)
+
+			if page_mem != None:
+				# Page from pages.img has higher priority
+				# than one from maped file on disk.
+				page = page_mem
+
+			if page == None:
+				# Hole
+				page = PAGESIZE*"\0"
+
+			# If it is a start or end page, we need to read
+			# only part of it.
+			if page_no == start_page:
+				n_skip = start - page_no*PAGESIZE
+				if start_page == end_page:
+					n_read = size
+				else:
+					n_read = PAGESIZE - n_skip
+			elif page_no == end_page:
+				n_skip = 0
+				n_read = end - page_no*PAGESIZE
+			else:
+				n_skip = 0
+				n_read = PAGESIZE
+
+			buf += page[n_skip : n_skip + n_read]
+
+		# Don't forget to close file.
+		if f != None:
+			f.close()
+
+		return buf
+
+	def _gen_cmdline(self, pid):
+		"""
+		Generate full command with arguments.
+		"""
+		mm = self.mms[pid]
+
+		vma = {}
+		vma["start"]	= mm["mm_arg_start"]
+		vma["end"]	= mm["mm_arg_end"]
+		# Dummy flags and status.
+		vma["flags"]	= 0
+		vma["status"]	= 0
+		size		= vma["end"] - vma["start"]
+
+		chunk = self._gen_mem_chunk(pid, vma, size)
+
+		# Replace all '\0's with spaces.
+		return chunk.replace('\0', ' ')
+
+	def _get_vma_dump_size(self, vma):
+		"""
+		Calculate amount of vma to put into core dump.
+		"""
+		if vma["status"] & status["VMA_AREA_VVAR"] or \
+		   vma["status"] & status["VMA_AREA_VSYSCALL"] or \
+		   vma["status"] & status["VMA_AREA_VDSO"]:
+			size = vma["end"] - vma["start"]
+		elif vma["prot"] == 0:
+			size = 0
+		elif vma["prot"] & prot["PROT_READ"] and \
+		     vma["prot"] & prot["PROT_EXEC"]:
+			size = PAGESIZE
+		elif vma["status"] & status["VMA_ANON_SHARED"] or \
+		     vma["status"] & status["VMA_FILE_SHARED"] or \
+		     vma["status"] & status["VMA_ANON_PRIVATE"] or \
+		     vma["status"] & status["VMA_FILE_PRIVATE"]:
+			size = vma["end"] - vma["start"]
+		else:
+			size = 0
+
+		return size
+
+	def _get_vma_flags(self, vma):
+		"""
+		Convert vma flags int elf flags.
+		"""
+		flags = 0
+
+		if vma['prot'] & prot["PROT_READ"]:
+			flags = flags | elf.PF_R
+
+		if vma['prot'] & prot["PROT_WRITE"]:
+			flags = flags | elf.PF_W
+
+		if vma['prot'] & prot["PROT_EXEC"]:
+			flags = flags | elf.PF_X
+
+		return flags
+
+	def _gen_vmas(self, pid):
+		"""
+		Generate vma contents for core dump for process pid.
+		"""
+		mm = self.mms[pid]
+
+		class vma_class:
+			data	= None
+			filesz	= None
+			memsz	= None
+			flags	= None
+			start	= None
+
+		vmas = []
+		for vma in mm["vmas"]:
+			size = self._get_vma_dump_size(vma)
+
+			chunk = self._gen_mem_chunk(pid, vma, size)
+
+			v = vma_class()
+			v.filesz	= self._get_vma_dump_size(vma)
+			v.data		= self._gen_mem_chunk(pid, vma, v.filesz)
+			v.memsz		= vma["end"] - vma["start"]
+			v.start		= vma["start"]
+			v.flags		= self._get_vma_flags(vma)
+
+			vmas.append(v)
+
+		return vmas
diff --git a/lib/py/coredump/elf.py b/lib/py/coredump/elf.py
new file mode 100644
index 0000000..070e479
--- /dev/null
+++ b/lib/py/coredump/elf.py
@@ -0,0 +1,526 @@
+# Define structures and constants for generating elf file.
+from ctypes import *
+
+Elf64_Half	= c_uint16	# typedef uint16_t Elf64_Half;
+Elf64_Word	= c_uint32	# typedef uint32_t Elf64_Word;
+Elf64_Addr	= c_uint64	# typedef uint64_t Elf64_Addr;
+Elf64_Off	= c_uint64	# typedef uint64_t Elf64_Off;
+Elf64_Xword	= c_uint64	# typedef uint64_t Elf64_Xword;
+
+# Elf64_Ehdr related constants.
+
+# e_ident size.
+EI_NIDENT	= 16		# #define EI_NIDENT (16)
+
+EI_MAG0		= 0		# #define EI_MAG0         0               /* File identification byte 0 index */
+ELFMAG0		= 0x7f		# #define ELFMAG0         0x7f            /* Magic number byte 0 */
+
+EI_MAG1		= 1		# #define EI_MAG1         1               /* File identification byte 1 index */
+ELFMAG1		= ord('E')	# #define ELFMAG1         'E'             /* Magic number byte 1 */
+
+EI_MAG2		= 2		# #define EI_MAG2         2               /* File identification byte 2 index */
+ELFMAG2		= ord('L')	# #define ELFMAG2         'L'             /* Magic number byte 2 */
+
+EI_MAG3		= 3		# #define EI_MAG3         3               /* File identification byte 3 index */
+ELFMAG3		= ord('F')	# #define ELFMAG3         'F'             /* Magic number byte 3 */
+
+EI_CLASS	= 4		# #define EI_CLASS        4               /* File class byte index */
+
+EI_DATA		= 5		# #define EI_DATA         5               /* Data encoding byte index */
+
+EI_VERSION	= 6		# #define EI_VERSION      6               /* File version byte index */
+
+ELFDATA2LSB	= 1		# #define ELFDATA2LSB     1               /* 2's complement, little endian */
+
+ELFCLASS64	= 2		# #define ELFCLASS64      2               /* 64-bit objects */
+
+# Legal values for e_type (object file type).
+ET_CORE		= 4		# #define ET_CORE         4               /* Core file */
+
+# Legal values for e_machine (architecture).
+EM_X86_64	= 62		# #define EM_X86_64       62              /* AMD x86-64 architecture */
+
+# Legal values for e_version (version).
+EV_CURRENT	= 1		# #define EV_CURRENT      1               /* Current version */
+
+class Elf64_Ehdr(Structure):			# typedef struct
+	_fields_ = [				# {
+	("e_ident",	c_ubyte*EI_NIDENT),	#   unsigned char e_ident[EI_NIDENT];
+	("e_type",	Elf64_Half),		#   Elf64_Half e_type;
+	("e_machine",	Elf64_Half),		#   Elf64_Half e_machine;
+	("e_version",	Elf64_Word),		#   Elf64_Word e_version;
+	("e_entry",	Elf64_Addr),		#   Elf64_Addr e_entry;
+	("e_phoff",	Elf64_Off),		#   Elf64_Off e_phoff;
+	("e_shoff",	Elf64_Off),		#   Elf64_Off e_shoff;
+	("e_flags",	Elf64_Word),		#   Elf64_Word e_flags;
+	("e_ehsize",	Elf64_Half),		#   Elf64_Half e_ehsize;
+	("e_phentsize",	Elf64_Half),		#   Elf64_Half e_phentsize;
+	("e_phnum",	Elf64_Half),		#   Elf64_Half e_phnum;
+	("e_shentsize",	Elf64_Half),		#   Elf64_Half e_shentsize;
+	("e_shnum",	Elf64_Half),		#   Elf64_Half e_shnum;
+	("e_shstrndx",	Elf64_Half)		#   Elf64_Half e_shstrndx;
+	]					# } Elf64_Ehdr;
+
+
+# Elf64_Phdr related constants.
+
+# Legal values for p_type (segment type).
+PT_LOAD	= 1		# #define PT_LOAD         1               /* Loadable program segment */
+PT_NOTE	= 4		# #define PT_NOTE         4               /* Auxiliary information */
+
+# Legal values for p_flags (segment flags).
+PF_X	= 1		# #define PF_X            (1 << 0)        /* Segment is executable */
+PF_W	= 1 << 1	# #define PF_W            (1 << 1)        /* Segment is writable */
+PF_R	= 1 << 2	# #define PF_R            (1 << 2)        /* Segment is readable */
+
+class Elf64_Phdr(Structure):			# typedef struct
+	_fields_ = [				# {
+	("p_type",	Elf64_Word),		#   Elf64_Word p_type;
+	("p_flags",	Elf64_Word),		#   Elf64_Word p_flags;
+	("p_offset",	Elf64_Off),		#   Elf64_Off p_offset;
+	("p_vaddr",	Elf64_Addr),		#   Elf64_Addr p_vaddr;
+	("p_paddr",	Elf64_Addr),		#   Elf64_Addr p_paddr;
+	("p_filesz",	Elf64_Xword),		#   Elf64_Xword p_filesz;
+	("p_memsz",	Elf64_Xword),		#   Elf64_Xword p_memsz;
+	("p_align",	Elf64_Xword),		#   Elf64_Xword p_align;
+	]					# } Elf64_Phdr;
+
+
+# Elf64_auxv_t related constants.
+
+class _Elf64_auxv_t_U(Union):
+	_fields_ = [
+	("a_val", c_uint64)
+	]
+
+class Elf64_auxv_t(Structure):			# typedef struct
+	_fields_ = [				# {
+	("a_type",	c_uint64),		#   uint64_t a_type;              /* Entry type */
+	("a_un",	_Elf64_auxv_t_U)	#   union
+						#     {
+						#       uint64_t a_val;           /* Integer value */
+						#       /* We use to have pointer elements added here.  We cannot do that,
+						#          though, since it does not work when using 32-bit definitions
+						#          on 64-bit platforms and vice versa.  */
+						#     } a_un;
+	]					# } Elf64_auxv_t;
+
+
+# Elf64_Nhdr related constants.
+
+NT_PRSTATUS	= 1		# #define NT_PRSTATUS     1               /* Contains copy of prstatus struct */
+NT_FPREGSET	= 2		# #define NT_FPREGSET     2               /* Contains copy of fpregset struct */
+NT_PRPSINFO	= 3		# #define NT_PRPSINFO     3               /* Contains copy of prpsinfo struct */
+NT_AUXV		= 6		# #define NT_AUXV         6               /* Contains copy of auxv array */
+NT_SIGINFO	= 0x53494749	# #define NT_SIGINFO      0x53494749      /* Contains copy of siginfo_t,
+#									     size might increase */
+NT_FILE		= 0x46494c45	# #define NT_FILE         0x46494c45      /* Contains information about mapped
+#									     files */
+NT_X86_XSTATE	= 0x202		# #define NT_X86_XSTATE   0x202           /* x86 extended state using xsave */
+
+class Elf64_Nhdr(Structure):		# typedef struct
+	_fields_ = [			# {
+	("n_namesz",	Elf64_Word),	#   Elf64_Word n_namesz;                  /* Length of the note's name.  */
+	("n_descsz",	Elf64_Word),	#   Elf64_Word n_descsz;                  /* Length of the note's descriptor.  */
+	("n_type",	Elf64_Word),	#   Elf64_Word n_type;                    /* Type of the note.  */
+	]				# } Elf64_Nhdr;
+
+
+# Elf64_Shdr related constants.
+
+class Elf64_Shdr(Structure):		# typedef struct
+	_fields_ = [			# {
+	("sh_name",	Elf64_Word),	#   Elf64_Word    sh_name;                /* Section name (string tbl index) */
+	("sh_type",	Elf64_Word),	#   Elf64_Word    sh_type;                /* Section type */
+	("sh_flags",	Elf64_Xword),	#   Elf64_Xword   sh_flags;               /* Section flags */
+	("sh_addr",	Elf64_Addr),	#   Elf64_Addr    sh_addr;                /* Section virtual addr at execution */
+	("sh_offset",	Elf64_Off),	#   Elf64_Off     sh_offset;              /* Section file offset */
+	("sh_size",	Elf64_Xword),	#   Elf64_Xword   sh_size;                /* Section size in bytes */
+	("sh_link",	Elf64_Word),	#   Elf64_Word    sh_link;                /* Link to another section */
+	("sh_info",	Elf64_Word),	#   Elf64_Word    sh_info;                /* Additional section information */
+	("sh_addralign",Elf64_Xword),	#   Elf64_Xword   sh_addralign;           /* Section alignment */
+	("sh_entsize",	Elf64_Xword)	#   Elf64_Xword   sh_entsize;             /* Entry size if section holds table */
+	]				# } Elf64_Shdr;
+
+
+# elf_prstatus related constants.
+
+# Signal info.
+class elf_siginfo(Structure):		# struct elf_siginfo
+	_fields_ = [			#   {
+	("si_signo",	c_int),		#     int si_signo;                       /* Signal number.  */
+	("si_code",	c_int),		#     int si_code;                        /* Extra code.  */
+	("si_errno",	c_int)		#     int si_errno;                       /* Errno.  */
+	]				#   };
+
+# A time value that is accurate to the nearest
+# microsecond but also has a range of years.
+class timeval(Structure):		# struct timeval
+	_fields_ = [			#   {
+	("tv_sec",	c_long),	#     __time_t tv_sec;            /* Seconds.  */
+	("tv_usec",	c_long)		#     __suseconds_t tv_usec;      /* Microseconds.  */
+	]				#   };
+
+class user_regs_struct(Structure):		# struct user_regs_struct
+	_fields_ = [				# {
+	("r15",		c_ulonglong),		#   __extension__ unsigned long long int r15;
+	("r14",		c_ulonglong),		#   __extension__ unsigned long long int r14;
+	("r13",		c_ulonglong),		#   __extension__ unsigned long long int r13;
+	("r12",		c_ulonglong),		#   __extension__ unsigned long long int r12;
+	("rbp",		c_ulonglong),		#   __extension__ unsigned long long int rbp;
+	("rbx",		c_ulonglong),		#   __extension__ unsigned long long int rbx;
+	("r11",		c_ulonglong),		#   __extension__ unsigned long long int r11;
+	("r10",		c_ulonglong),		#   __extension__ unsigned long long int r10;
+	("r9",		c_ulonglong),		#   __extension__ unsigned long long int r9;
+	("r8",		c_ulonglong),		#   __extension__ unsigned long long int r8;
+	("rax",		c_ulonglong),		#   __extension__ unsigned long long int rax;
+	("rcx",		c_ulonglong),		#   __extension__ unsigned long long int rcx;
+	("rdx",		c_ulonglong),		#   __extension__ unsigned long long int rdx;
+	("rsi",		c_ulonglong),		#   __extension__ unsigned long long int rsi;
+	("rdi",		c_ulonglong),		#   __extension__ unsigned long long int rdi;
+	("orig_rax",	c_ulonglong),		#   __extension__ unsigned long long int orig_rax;
+	("rip",		c_ulonglong),		#   __extension__ unsigned long long int rip;
+	("cs",		c_ulonglong),		#   __extension__ unsigned long long int cs;
+	("eflags",	c_ulonglong),		#   __extension__ unsigned long long int eflags;
+	("rsp",		c_ulonglong),		#   __extension__ unsigned long long int rsp;
+	("ss",		c_ulonglong),		#   __extension__ unsigned long long int ss;
+	("fs_base",	c_ulonglong),		#   __extension__ unsigned long long int fs_base;
+	("gs_base",	c_ulonglong),		#   __extension__ unsigned long long int gs_base;
+	("ds",		c_ulonglong),		#   __extension__ unsigned long long int ds;
+	("es",		c_ulonglong),		#   __extension__ unsigned long long int es;
+	("fs",		c_ulonglong),		#   __extension__ unsigned long long int fs;
+	("gs",		c_ulonglong)		#   __extension__ unsigned long long int gs;
+	]					# };
+
+#elf_greg_t	= c_ulonglong
+#ELF_NGREG = sizeof(user_regs_struct)/sizeof(elf_greg_t)
+#elf_gregset_t = elf_greg_t*ELF_NGREG
+elf_gregset_t = user_regs_struct
+
+class elf_prstatus(Structure):		# struct elf_prstatus
+	_fields_ = [			#   {
+	("pr_info",	elf_siginfo),	#     struct elf_siginfo pr_info;         /* Info associated with signal.  */
+	("pr_cursig",	c_short),	#     short int pr_cursig;                /* Current signal.  */
+	("pr_sigpend",	c_ulong),	#     unsigned long int pr_sigpend;       /* Set of pending signals.  */
+	("pr_sighold",	c_ulong),	#     unsigned long int pr_sighold;       /* Set of held signals.  */
+	("pr_pid",	c_int),		#     __pid_t pr_pid;
+	("pr_ppid",	c_int),		#     __pid_t pr_ppid;
+	("pr_pgrp",	c_int),		#     __pid_t pr_pgrp;
+	("pr_sid",	c_int),		#     __pid_t pr_sid;
+	("pr_utime",	timeval),	#     struct timeval pr_utime;            /* User time.  */
+	("pr_stime",	timeval),	#     struct timeval pr_stime;            /* System time.  */
+	("pr_cutime",	timeval),	#     struct timeval pr_cutime;           /* Cumulative user time.  */
+	("pr_cstime",	timeval),	#     struct timeval pr_cstime;           /* Cumulative system time.  */
+	("pr_reg",	elf_gregset_t),	#     elf_gregset_t pr_reg;               /* GP registers.  */
+	("pr_fpvalid",	c_int)		#     int pr_fpvalid;                     /* True if math copro being used.  */
+	]				#   };
+
+
+# elf_prpsinfo related constants.
+
+ELF_PRARGSZ	= 80			# #define ELF_PRARGSZ     (80)    /* Number of chars for args.  */
+
+class elf_prpsinfo(Structure):			# struct elf_prpsinfo
+	_fields_ = [				#   {
+	("pr_state",	c_byte),		#     char pr_state;                      /* Numeric process state.  */
+	("pr_sname",	c_char),		#     char pr_sname;                      /* Char for pr_state.  */
+	("pr_zomb",	c_byte),		#     char pr_zomb;                       /* Zombie.  */
+	("pr_nice",	c_byte),		#     char pr_nice;                       /* Nice val.  */
+	("pr_flag",	c_ulong),		#     unsigned long int pr_flag;          /* Flags.  */
+						# #if __WORDSIZE == 32
+						#     unsigned short int pr_uid;
+						#     unsigned short int pr_gid;
+						# #else
+	("pr_uid",	c_uint),		#     unsigned int pr_uid;
+	("pr_gid",	c_uint),		#     unsigned int pr_gid;
+						# #endif
+	("pr_pid",	c_int),			#     int pr_pid, pr_ppid, pr_pgrp, pr_sid;
+	("pr_ppid",	c_int),
+	("pr_pgrp",	c_int),
+	("pr_sid",	c_int),
+						#     /* Lots missing */
+	("pr_fname",	c_char*16),		#     char pr_fname[16];                  /* Filename of executable.  */
+	("pr_psargs",	c_char*ELF_PRARGSZ)	#     char pr_psargs[ELF_PRARGSZ];        /* Initial part of arg list.  */
+	]					#   };
+
+
+class user_fpregs_struct(Structure):		# struct user_fpregs_struct
+	_fields_ = [				# {
+	("cwd",		c_ushort),		#   unsigned short int    cwd;
+	("swd",		c_ushort),		#   unsigned short int    swd;
+	("ftw",		c_ushort),		#   unsigned short int    ftw;
+	("fop",		c_ushort),		#   unsigned short int    fop;
+	("rip",		c_ulonglong),		#   __extension__ unsigned long long int rip;
+	("rdp",		c_ulonglong),		#   __extension__ unsigned long long int rdp;
+	("mxcsr",	c_uint),		#   unsigned int          mxcsr;
+	("mxcr_mask",	c_uint),		#   unsigned int          mxcr_mask;
+	("st_space",	c_uint*32),		#   unsigned int          st_space[32];   /* 8*16 bytes for each FP-reg = 128 bytes */
+	("xmm_space",	c_uint*64),		#   unsigned int          xmm_space[64];  /* 16*16 bytes for each XMM-reg = 256 bytes */
+	("padding",	c_uint*24),		#   unsigned int          padding[24];
+	]					# };
+
+
+elf_fpregset_t = user_fpregs_struct
+
+
+# siginfo_t related constants.
+
+_SI_MAX_SIZE	= 128
+_SI_PAD_SIZE	= (_SI_MAX_SIZE/sizeof(c_int)) - 4
+
+					#          /* kill().  */
+class _siginfo_t_U_kill(Structure):	#         struct
+	_fields_ = [			#           {
+	("si_pid",	c_int),		#             __pid_t si_pid;     /* Sending process ID.  */
+	("si_uid",	c_uint)		#             __uid_t si_uid;     /* Real user ID of sending process.  */
+	]				#           } _kill;
+
+
+
+# Type for data associated with a signal.
+class sigval_t(Union):			# typedef union sigval
+	_fields_ = [			#   {
+	("sival_int", c_int),		#     int sival_int;
+	("sical_ptr", c_void_p),	#     void *sival_ptr;
+	]				#   } sigval_t;
+
+					#         /* POSIX.1b timers.  */
+class _siginfo_t_U_timer(Structure):	#         struct
+	_fields_ = [			#           {
+	("si_tid",	c_int),		#             int si_tid;         /* Timer ID.  */
+	("si_overrun",	c_int),		#             int si_overrun;     /* Overrun count.  */
+	("si_sigval",	sigval_t)	#             sigval_t si_sigval; /* Signal value.  */
+	]				#           } _timer;
+
+
+						#         /* POSIX.1b signals.  */
+class _siginfo_t_U_rt(Structure):		#         struct
+	_fields_ = [				#           {
+	("si_pid",	c_int),			#             __pid_t si_pid;     /* Sending process ID.  */
+	("si_uid",	c_uint),		#             __uid_t si_uid;     /* Real user ID of sending process.  */
+	("si_sigval",	sigval_t)		#             sigval_t si_sigval; /* Signal value.  */
+	]					#           } _rt;
+
+
+						#         /* SIGCHLD.  */
+class _siginfo_t_U_sigchld(Structure):		#         struct
+	_fields_ = [				#           {
+	("si_pid",	c_int),			#             __pid_t si_pid;     /* Which child.  */
+	("si_uid",	c_uint),		#             __uid_t si_uid;     /* Real user ID of sending process.  */
+	("si_status",	c_int),			#             int si_status;      /* Exit value or signal.  */
+	("si_utime",	c_long),		#             __sigchld_clock_t si_utime;
+	("si_stime",	c_long)			#             __sigchld_clock_t si_stime;
+	]					#           } _sigchld;
+
+						#         /* SIGILL, SIGFPE, SIGSEGV, SIGBUS.  */
+class _siginfo_t_U_sigfault(Structure):		#         struct
+	_fields_ = [				#           {
+	("si_addr",	c_void_p),		#             void *si_addr;      /* Faulting insn/memory ref.  */
+	("si_addr_lsb",	c_short)		#             short int si_addr_lsb;      /* Valid LSB of the reported address.  */
+	]					#           } _sigfault;
+
+						#         /* SIGPOLL.  */
+class _siginfo_t_U_sigpoll(Structure):		#         struct
+	_fields_ = [				#           {
+	("si_band",	c_long),		#             long int si_band;   /* Band event for SIGPOLL.  */
+	("si_fd",	c_int)			#             int si_fd;
+	]					#           } _sigpoll;
+
+
+						# 	        /* SIGSYS.  */
+class _siginfo_t_U_sigsys(Structure):		#         struct
+	_fields_ = [				#           {
+	("_call_addr",	c_void_p),		#             void *_call_addr;   /* Calling user insn.  */
+	("_syscall",	c_int),			#             int _syscall;       /* Triggering system call number.  */
+	("_arch",	c_uint)			#             unsigned int _arch; /* AUDIT_ARCH_* of syscall.  */
+	]					#           } _sigsys;
+
+
+class _siginfo_t_U(Union):			#     union
+	_fields_ = [				#       {
+	("_pad",	c_int*_SI_PAD_SIZE),	#         int _pad[__SI_PAD_SIZE];
+						#
+						#          /* kill().  */
+	("_kill",	_siginfo_t_U_kill),	#         struct
+						#           {
+						#             __pid_t si_pid;     /* Sending process ID.  */
+						#             __uid_t si_uid;     /* Real user ID of sending process.  */
+						#           } _kill;
+						#
+						#         /* POSIX.1b timers.  */
+	("_timer",	_siginfo_t_U_timer),	#         struct
+						#           {
+						#             int si_tid;         /* Timer ID.  */
+						#             int si_overrun;     /* Overrun count.  */
+						#             sigval_t si_sigval; /* Signal value.  */
+						#           } _timer;
+						#
+						#         /* POSIX.1b signals.  */
+	("_rt",		_siginfo_t_U_rt),	#         struct
+						#           {
+						#             __pid_t si_pid;     /* Sending process ID.  */
+						#             __uid_t si_uid;     /* Real user ID of sending process.  */
+						#             sigval_t si_sigval; /* Signal value.  */
+						#           } _rt;
+						#
+						#         /* SIGCHLD.  */
+	("_sigchld",	_siginfo_t_U_sigchld),	#         struct
+						#           {
+						#             __pid_t si_pid;     /* Which child.  */
+						#             __uid_t si_uid;     /* Real user ID of sending process.  */
+						#             int si_status;      /* Exit value or signal.  */
+						#             __sigchld_clock_t si_utime;
+						#             __sigchld_clock_t si_stime;
+						#           } _sigchld;
+						#
+						#         /* SIGILL, SIGFPE, SIGSEGV, SIGBUS.  */
+	("_sigfault",	_siginfo_t_U_sigfault),	#         struct
+						#           {
+						#             void *si_addr;      /* Faulting insn/memory ref.  */
+						#             short int si_addr_lsb;      /* Valid LSB of the reported address.  */
+						#           } _sigfault;
+						#
+						#         /* SIGPOLL.  */
+	("_sigpoll",	_siginfo_t_U_sigpoll),	#         struct
+						#           {
+						#             long int si_band;   /* Band event for SIGPOLL.  */
+						#             int si_fd;
+						#           } _sigpoll;
+						#
+						# 	        /* SIGSYS.  */
+	("_sigsys",	_siginfo_t_U_sigpoll)	#         struct
+						#           {
+						#             void *_call_addr;   /* Calling user insn.  */
+						#             int _syscall;       /* Triggering system call number.  */
+						#             unsigned int _arch; /* AUDIT_ARCH_* of syscall.  */
+						#           } _sigsys;
+	]					#       } _sifields;
+
+class siginfo_t(Structure):		# typedef struct
+	_fields_ = [			#   {
+	("si_signo",	c_int),		#     int si_signo;               /* Signal number.  */
+	("si_errno",	c_int),		#     int si_errno;               /* If non-zero, an errno value associated with
+					#                                    this signal, as defined in <errno.h>.  */
+	("si_code",	c_int),		#     int si_code;                /* Signal code.  */
+					#
+	("_sifields",	_siginfo_t_U)	#     union
+					#       {
+					#         int _pad[__SI_PAD_SIZE];
+					#
+					#          /* kill().  */
+					#         struct
+					#           {
+					#             __pid_t si_pid;     /* Sending process ID.  */
+					#             __uid_t si_uid;     /* Real user ID of sending process.  */
+					#           } _kill;
+					#
+					#         /* POSIX.1b timers.  */
+					#         struct
+					#           {
+					#             int si_tid;         /* Timer ID.  */
+					#             int si_overrun;     /* Overrun count.  */
+					#             sigval_t si_sigval; /* Signal value.  */
+					#           } _timer;
+					#
+					#         /* POSIX.1b signals.  */
+					#         struct
+					#           {
+					#             __pid_t si_pid;     /* Sending process ID.  */
+					#             __uid_t si_uid;     /* Real user ID of sending process.  */
+					#             sigval_t si_sigval; /* Signal value.  */
+					#           } _rt;
+					#
+					#         /* SIGCHLD.  */
+					#         struct
+					#           {
+					#             __pid_t si_pid;     /* Which child.  */
+					#             __uid_t si_uid;     /* Real user ID of sending process.  */
+					#             int si_status;      /* Exit value or signal.  */
+					#             __sigchld_clock_t si_utime;
+					#             __sigchld_clock_t si_stime;
+					#           } _sigchld;
+					#
+					#         /* SIGILL, SIGFPE, SIGSEGV, SIGBUS.  */
+					#         struct
+					#           {
+					#             void *si_addr;      /* Faulting insn/memory ref.  */
+					#             short int si_addr_lsb;      /* Valid LSB of the reported address.  */
+					#           } _sigfault;
+					#
+					#         /* SIGPOLL.  */
+					#         struct
+					#           {
+					#             long int si_band;   /* Band event for SIGPOLL.  */
+					#             int si_fd;
+					#           } _sigpoll;
+					#
+					# 	        /* SIGSYS.  */
+					#         struct
+					#           {
+					#             void *_call_addr;   /* Calling user insn.  */
+					#             int _syscall;       /* Triggering system call number.  */
+					#             unsigned int _arch; /* AUDIT_ARCH_* of syscall.  */
+					#           } _sigsys;
+					#       } _sifields;
+	]				#   } siginfo_t __SI_ALIGNMENT;
+
+
+# xsave related.
+
+class ymmh_struct(Structure):		# struct ymmh_struct {
+	_fields_ = [
+	("ymmh_space",	64*c_uint)	#         u32                             ymmh_space[64];
+	]				# } __packed;
+
+
+class xsave_hdr_struct(Structure):	# struct xsave_hdr_struct {
+	_fields_ = [
+	("xstate_bv",	c_ulonglong),	#         u64                             xstate_bv;
+	("reserved1",	c_ulonglong*2),	#         u64                             reserved1[2];
+	("reserved2",	c_ulonglong*5)	#         u64                             reserved2[5];
+	]				# } __packed;
+
+
+class i387_fxsave_struct(Structure):	# struct i387_fxsave_struct {
+	_fields_ = [
+	("cwd",		c_ushort),	#         u16                             cwd; /* Control Word                    */
+	("swd",		c_ushort),	#         u16                             swd; /* Status Word                     */
+	("twd",		c_ushort),	#         u16                             twd; /* Tag Word                        */
+	("fop",		c_ushort),	#         u16                             fop; /* Last Instruction Opcode         */
+					#         union {
+					#                 struct {
+	("rip",		c_ulonglong),	#                         u64             rip; /* Instruction Pointer             */
+	("rdp",		c_ulonglong),	#                         u64             rdp; /* Data Pointer                    */
+					#                 };
+					#                 struct {
+					#                         u32             fip; /* FPU IP Offset                   */
+					#                         u32             fcs; /* FPU IP Selector                 */
+					#                         u32             foo; /* FPU Operand Offset              */
+					#                         u32             fos; /* FPU Operand Selector            */
+					#                 };
+					#         };
+	("mxcsr",	c_uint),	#         u32                             mxcsr;          /* MXCSR Register State */
+	("mxcsr_mask",	c_uint),	#         u32                             mxcsr_mask;     /* MXCSR Mask           */
+					#
+					#         /* 8*16 bytes for each FP-reg = 128 bytes                               */
+	("st_space",	c_uint*32),	#         u32                             st_space[32];
+#
+					#         /* 16*16 bytes for each XMM-reg = 256 bytes                             */
+	("xmm_space",	c_uint*64),	#         u32                             xmm_space[64];
+					#
+	("padding",	c_uint*12),	#         u32                             padding[12];
+					#
+					#         union {
+	("padding1",	c_uint*12)	#                 u32                     padding1[12];
+					#                 u32                     sw_reserved[12];
+					#         };
+					#
+	]				# } __aligned(16);
+
+
+class elf_xsave_struct(Structure):		# struct xsave_struct {
+	_fields_ = [
+	("i387",	i387_fxsave_struct),	#         struct i387_fxsave_struct       i387;
+	("xsave_hdr",	xsave_hdr_struct),	#         struct xsave_hdr_struct         xsave_hdr;
+	("ymmh",	ymmh_struct)		#         struct ymmh_struct              ymmh;
+	]					# } __aligned(FP_MIN_ALIGN_BYTES) __packed;
-- 
2.5.0



More information about the CRIU mailing list