[CRIU] [PATCH 2/3] crit: add core-dump feature
Ruslan Kuprieiev
kupruser at gmail.com
Sun Apr 19 11:50:05 PDT 2015
crit core-dump is to be used to produce valid elf core dump
from criu images. It is already able to produce core dump that
is readable and can be used by objdump, readelf and gdb.
Still, it is not perfect and lacks some vma contents(vsyscall
and vvar) and some core notes are not fullfilled.
It is also worth noting that for now only x86_64 architecture
is supported.
Signed-off-by: Ruslan Kuprieiev <kupruser at gmail.com>
---
crit | 18 +-
pycriu/images/__init__.py | 1 +
pycriu/images/core_dump.py | 766 +++++++++++++++++++++++++++++++++++++++++++++
pycriu/images/elf.py | 526 +++++++++++++++++++++++++++++++
4 files changed, 1310 insertions(+), 1 deletion(-)
create mode 100644 pycriu/images/core_dump.py
create mode 100644 pycriu/images/elf.py
diff --git a/crit b/crit
index 88f3b8e..85add1b 100755
--- a/crit
+++ b/crit
@@ -1,6 +1,6 @@
#!/usr/bin/env python
import argparse
-import sys
+import sys, os
import json
import pycriu
@@ -34,6 +34,11 @@ def encode(opts):
img = json.load(inf(opts))
pycriu.images.dump(img, outf(opts))
+def core_dump(opts):
+ dump = pycriu.images.core_generator()
+ dump.parse_images(os.path.realpath(opts['in']), opts['pid'])
+ dump.write_cores(os.path.realpath(opts['out']), opts['pid'])
+
def main():
desc = 'CRiu Image Tool'
parser = argparse.ArgumentParser(description=desc,
@@ -66,6 +71,17 @@ def main():
help = 'where to put criu image in binary format (stdout by default)')
encode_parser.set_defaults(func=encode)
+ # Core dump
+ core_parser = subparsers.add_parser('core-dump',
+ help = 'generate core dumps from criu images')
+ core_parser.add_argument('-i', '--in', default = '.',
+ help = 'directory where to get images from')
+ core_parser.add_argument('-p', '--pid', type = int,
+ help = 'generate core dump of a process identified by PID')
+ core_parser.add_argument('-o', '--out', default = '.',
+ help = 'directory to write core dump to')
+ core_parser.set_defaults(func=core_dump)
+
opts = vars(parser.parse_args())
opts["func"](opts)
diff --git a/pycriu/images/__init__.py b/pycriu/images/__init__.py
index 379943b..01a8c98 100644
--- a/pycriu/images/__init__.py
+++ b/pycriu/images/__init__.py
@@ -1,3 +1,4 @@
from magic import *
from images import *
from pb import *
+from core_dump import *
diff --git a/pycriu/images/core_dump.py b/pycriu/images/core_dump.py
new file mode 100644
index 0000000..7734d6a
--- /dev/null
+++ b/pycriu/images/core_dump.py
@@ -0,0 +1,766 @@
+# 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
+import images
+
+PAGESIZE = 4096
+
+class elf_note:
+ nhdr = None # Elf_Nhdr;
+ owner = None # i.e. CORE or LINUX;
+ data = None # Ctypes structure with note data;
+
+
+class core_dump:
+ """
+ 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.read())
+
+ buf.seek(0)
+ f.write(buf.read())
+
+class core_generator:
+ """
+ Generate core dump from criu images.
+ """
+ cores = {} # core_dumps 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 parse_images(self, imgs_dir, pid = None):
+ """
+ Parse criu images stored in directory imgs_dir to fill core dump.
+ Specify pid if you don't want to generate core dump for each process
+ in a tree.
+ """
+ self._imgs_dir = imgs_dir
+ self._pstree = self._img_open_and_strip("pstree")
+
+ pids = []
+ if pid == None:
+ # If no pid is specified we will generate core dumps for
+ # each pid in process tree.
+ for p in self._pstree:
+ pids.append(p["pid"])
+ else:
+ pids.append(pid)
+
+ for p in pids:
+ self.cores[p] = self._gen_core(p)
+
+
+ def write_cores(self, cores_dir, pid = None):
+ """
+ Write core dumpt to cores_dir directory. Specify pid to choose
+ core dump of only one process.
+ """
+ for p in self.cores:
+ if pid and p != pid:
+ continue
+ with open(cores_dir+"/"+"core."+str(p), 'w+') as f:
+ self.cores[p].write(f)
+
+ def _gen_core(self, pid):
+ """
+ Generate core dump for pid.
+ """
+ cd = core_dump()
+
+ # 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 = filter(lambda x: x["pid"] == pid, self._pstree)[0]
+ creds = self._img_open_and_strip("creds", True, pid)
+ core = self._img_open_and_strip("core", True, 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 = creds["uid"]
+ prpsinfo.pr_gid = 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 = core["tc"]["cmdline"]
+
+ 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._img_open_and_strip("core", True, tid)
+ regs = core["thread_info"]["gpregs"]
+ pstree = filter(lambda x: x["pid"] == pid, self._pstree)[0]
+
+ 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._img_open_and_strip("core", True, 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._img_open_and_strip("core", True, 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._img_open_and_strip("mm", True, 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._img_open_and_strip("mm", True, 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._img_open_and_strip("reg-files", False)
+ 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_notes(self, pid):
+ """
+ Generate notes for core dump of process pid.
+ """
+ notes = []
+
+ notes.append(self._gen_prpsinfo(pid))
+
+ threads = filter(lambda x: x["pid"] == pid, self._pstree)[0]["threads"]
+
+ # Main thread first
+ notes.append(self._gen_prstatus(pid, pid))
+ notes.append(self._gen_fpregset(pid, pid))
+ # Optional xsave
+ n = self._gen_x86_xstate(pid, pid)
+ if n != None:
+ notes.append(n)
+ notes.append(self._gen_siginfo(pid, pid))
+
+ # Then other threads
+ for tid in threads:
+ if tid == pid:
+ continue
+
+ notes.append(self._gen_prstatus(pid, tid))
+ notes.append(self._gen_fpregset(pid, tid))
+ # Optional xsave
+ n = self._gen_x86_xstate(pid, tid)
+ if n != None:
+ notes.append(n)
+ notes.append(self._gen_siginfo(pid, tid))
+
+ notes.append(self._gen_auxv(pid))
+ notes.append(self._gen_files(pid))
+
+ return notes
+
+ def _gen_mem_chunk(self, pid, vma, size):
+ """
+ Obtain vma contents for process pid.
+ """
+ pagemap = self._img_open_and_strip("pagemap", False, pid)
+
+ MAP_GROWSDOWN = 0x0100
+ stack = False
+ # Stack-like vma should be handled in a special way.
+ if vma["flags"] & MAP_GROWSDOWN:
+ stack = True
+
+ start = vma["start"]
+ end = vma["end"]
+ size = end - start
+
+ # For stack it's vma["end"] is actually it's start, so
+ # we should look for it instead of vma["start"] as it
+ # might be located in zeroed pages, that we don't bring
+ # to out pages.img.
+ if stack:
+ addr = end
+ else:
+ addr = start
+
+ # First entry is pagemap_head, we will need it later to open
+ # proper pages.img.
+ pages_id = pagemap[0]["pages_id"]
+ off = 0
+ for m in pagemap[1:]:
+ if m["vaddr"] <= addr and \
+ m["vaddr"] + m["nr_pages"]*PAGESIZE >= addr:
+ if stack:
+ zeroes_size = size - (end - m["vaddr"])
+ else:
+ zeroes_size = size - (m["vaddr"]+m["nr_pages"]*PAGESIZE - start)
+ off += start - m["vaddr"]
+
+ if zeroes_size < 0:
+ zeroes_size = 0
+
+ read_size = size - zeroes_size
+
+ # This is a padding for thouse zeroed pages we
+ # didn't bring to our images.
+ scratch = (ctypes.c_char * zeroes_size)()
+ ctypes.memset(ctypes.addressof(scratch), 0, ctypes.sizeof(scratch))
+
+ if "in_parent" in m and m["in_parent"] == True:
+ ppid = filter(lambda x: x["pid"] == pid, self._pstree)["ppid"]
+ return self._gen_mem_chunk(ppid, vma, size)
+ else:
+ buf = io.BytesIO()
+
+ # For stack we should write padding first
+ if stack and scratch:
+ buf.write(scratch)
+ with open(self._imgs_dir+"/"+"pages-"+str(pages_id)+".img") as f:
+ f.seek(off)
+ buf.write(f.read(size - zeroes_size))
+
+ # and for non-stack -- after writing actual pages.
+ if not stack and scratch:
+ buf.write(scratch)
+
+ buf.seek(0)
+ return buf
+
+ else:
+ off += PAGESIZE*m["nr_pages"]
+
+
+ def _gen_file_chunk(self, vma, size):
+ """
+ Obtain maped file vma contents.
+ """
+ shmid = vma["shmid"]
+ off = vma["pgoff"]
+
+ files = self._img_open_and_strip("reg-files", False)
+ fname = filter(lambda x: x["id"] == shmid, files)[0]["name"]
+
+ buf = io.BytesIO()
+ with open(fname) as f:
+ f.seek(off)
+ buf.write(f.read(size))
+ buf.seek(0)
+
+ return buf
+
+ def _gen_vmas(self, pid):
+ """
+ Generate vma contents for core dump for process pid.
+ """
+ mm = self._img_open_and_strip("mm", True, pid)
+
+ class vma_class:
+ data = None
+ filesz = None
+ memsz = None
+ flags = None
+ start = None
+
+ vmas = []
+ for vma in mm["vmas"]:
+ 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
+ }
+
+ 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
+
+ if size != 0:
+ if vma["status"] & status["VMA_AREA_VVAR"]:
+ #FIXME this is what gdb does, as vvar vma
+ # is not readable from userspace?
+ chunk = io.BytesIO("\0"*size)
+ elif vma["status"] & status["VMA_AREA_VSYSCALL"]:
+ #FIXME need to dump it with criu or read from
+ # current process.
+ chunk = io.BytesIO("\0"*size)
+ elif vma["status"] & status["VMA_FILE_SHARED"] or \
+ vma["status"] & status["VMA_FILE_PRIVATE"]:
+ chunk = self._gen_file_chunk(vma, size)
+ else:
+ chunk = self._gen_mem_chunk(pid, vma, size)
+ else:
+ chunk = io.BytesIO()
+
+ if chunk == None:
+ raise Exception("No chunk for vma "+hex(vma["start"])+" "+hex(vma["end"]))
+
+ v = vma_class()
+ v.data = chunk
+ v.filesz = size
+ v.memsz = vma["end"] - vma["start"]
+ v.start = vma["start"]
+ v.flags = elf.PF_R if vma['prot'] & prot["PROT_READ"] else 0
+ if vma['prot'] & prot["PROT_WRITE"]:
+ v.flags = v.flags | elf.PF_W
+ if vma['prot'] & prot["PROT_EXEC"]:
+ v.flags = v.flags | elf.PF_X
+
+ vmas.append(v)
+
+ return vmas
diff --git a/pycriu/images/elf.py b/pycriu/images/elf.py
new file mode 100644
index 0000000..070e479
--- /dev/null
+++ b/pycriu/images/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;
--
1.9.1
More information about the CRIU
mailing list