Commit 8a71a4a2 authored by Ruslan Kuprieiev's avatar Ruslan Kuprieiev Committed by Pavel Emelyanov

criu-coredump: merge criu-coredump project

This patch introduces a new subproject called "criu-coredump". The name
is pretty much self-explanatory, it allows generating coredumps from
criu images. Coredumps 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 machines.
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: 's avatarRuslan Kuprieiev <kupruser@gmail.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent b28f93ef
#!/usr/bin/env python
import argparse
import os
import criu_coredump
def coredump(opts):
generator = criu_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 core dump'
parser = argparse.ArgumentParser(description=desc,
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-i',
'--in',
default = '.',
help = 'directory where to get images from')
parser.add_argument('-p',
'--pid',
type = int,
help = 'generate coredump for specific pid(all pids py default)')
parser.add_argument('-o',
'--out',
default = '.',
help = 'directory to write coredumps to')
opts = vars(parser.parse_args())
coredump(opts)
if __name__ == '__main__':
main()
from coredump import *
import elf
# 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 pycriu 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
# 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;
../lib/py/
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment