mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-01-23 02:14:37 +00:00
coredump: enable coredump generation on aarch64
Add relevant elf header constants and notes for the aarch64 platform to enable coredump generation. Signed-off-by: समीर सिंह Sameer Singh <lumarzeli30@gmail.com>
This commit is contained in:
parent
030fa4affd
commit
da90b33a42
4 changed files with 178 additions and 52 deletions
|
|
@ -6,6 +6,8 @@ import sys
|
|||
|
||||
import criu_coredump
|
||||
|
||||
PLATFORMS = ["aarch64", "x86_64"]
|
||||
|
||||
|
||||
def coredump(opts):
|
||||
generator = criu_coredump.coredump_generator()
|
||||
|
|
@ -37,8 +39,8 @@ def main():
|
|||
|
||||
opts = vars(parser.parse_args())
|
||||
|
||||
if platform.machine() != 'x86_64':
|
||||
print('ERROR: %s only supported on x86_64' % sys.argv[0])
|
||||
if platform.machine() not in PLATFORMS:
|
||||
print("ERROR: %s is only supported on: %s" % (sys.argv[0], ', '.join(PLATFORMS)))
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
import io
|
||||
import sys
|
||||
import ctypes
|
||||
import platform
|
||||
|
||||
from pycriu import images
|
||||
from . import elf
|
||||
|
|
@ -130,6 +131,11 @@ class coredump_generator:
|
|||
reg_files = None # reg-files;
|
||||
pagemaps = {} # pagemap by pid;
|
||||
|
||||
# thread info key based on the current arch
|
||||
thread_info_key = {"aarch64": "ti_aarch64", "x86_64": "thread_info"}
|
||||
|
||||
machine = platform.machine() # current arch
|
||||
|
||||
def _img_open_and_strip(self, name, single=False, pid=None):
|
||||
"""
|
||||
Load criu image and strip it from magic and redundant list.
|
||||
|
|
@ -213,7 +219,7 @@ class coredump_generator:
|
|||
ehdr.e_ident[elf.EI_VERSION] = elf.EV_CURRENT
|
||||
|
||||
ehdr.e_type = elf.ET_CORE
|
||||
ehdr.e_machine = elf.EM_X86_64
|
||||
ehdr.e_machine = self._get_e_machine()
|
||||
ehdr.e_version = elf.EV_CURRENT
|
||||
ehdr.e_phoff = ctypes.sizeof(elf.Elf64_Ehdr())
|
||||
ehdr.e_ehsize = ctypes.sizeof(elf.Elf64_Ehdr())
|
||||
|
|
@ -224,6 +230,13 @@ class coredump_generator:
|
|||
|
||||
return ehdr
|
||||
|
||||
def _get_e_machine(self):
|
||||
"""
|
||||
Get the e_machine field based on the current architecture.
|
||||
"""
|
||||
e_machine_dict = {"aarch64": elf.EM_AARCH64, "x86_64": elf.EM_X86_64}
|
||||
return e_machine_dict[self.machine]
|
||||
|
||||
def _gen_phdrs(self, pid, notes, vmas):
|
||||
"""
|
||||
Generate program headers for process pid.
|
||||
|
|
@ -332,7 +345,7 @@ class coredump_generator:
|
|||
Generate NT_PRSTATUS note for thread tid of process pid.
|
||||
"""
|
||||
core = self.cores[tid]
|
||||
regs = core["thread_info"]["gpregs"]
|
||||
regs = self._get_gpregs(core)
|
||||
pstree = self.pstree[pid]
|
||||
|
||||
prstatus = elf.elf_prstatus()
|
||||
|
|
@ -345,33 +358,7 @@ class coredump_generator:
|
|||
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"]
|
||||
self._set_pr_regset(prstatus.pr_reg, regs)
|
||||
|
||||
nhdr = elf.Elf64_Nhdr()
|
||||
nhdr.n_namesz = 5
|
||||
|
|
@ -385,28 +372,64 @@ class coredump_generator:
|
|||
|
||||
return note
|
||||
|
||||
def _get_gpregs(self, core):
|
||||
"""
|
||||
Get the general purpose registers based on the current architecture.
|
||||
"""
|
||||
thread_info_key = self.thread_info_key[self.machine]
|
||||
thread_info = core[thread_info_key]
|
||||
|
||||
return thread_info["gpregs"]
|
||||
|
||||
def _set_pr_regset(self, pr_reg, regs):
|
||||
"""
|
||||
Set the pr_reg struct based on the current architecture.
|
||||
"""
|
||||
if self.machine == "aarch64":
|
||||
pr_reg.regs = (ctypes.c_ulonglong * len(regs["regs"]))(*regs["regs"])
|
||||
pr_reg.sp = regs["sp"]
|
||||
pr_reg.pc = regs["pc"]
|
||||
pr_reg.pstate = regs["pstate"]
|
||||
elif self.machine == "x86_64":
|
||||
pr_reg.r15 = regs["r15"]
|
||||
pr_reg.r14 = regs["r14"]
|
||||
pr_reg.r13 = regs["r13"]
|
||||
pr_reg.r12 = regs["r12"]
|
||||
pr_reg.rbp = regs["bp"]
|
||||
pr_reg.rbx = regs["bx"]
|
||||
pr_reg.r11 = regs["r11"]
|
||||
pr_reg.r10 = regs["r10"]
|
||||
pr_reg.r9 = regs["r9"]
|
||||
pr_reg.r8 = regs["r8"]
|
||||
pr_reg.rax = regs["ax"]
|
||||
pr_reg.rcx = regs["cx"]
|
||||
pr_reg.rdx = regs["dx"]
|
||||
pr_reg.rsi = regs["si"]
|
||||
pr_reg.rdi = regs["di"]
|
||||
pr_reg.orig_rax = regs["orig_ax"]
|
||||
pr_reg.rip = regs["ip"]
|
||||
pr_reg.cs = regs["cs"]
|
||||
pr_reg.eflags = regs["flags"]
|
||||
pr_reg.rsp = regs["sp"]
|
||||
pr_reg.ss = regs["ss"]
|
||||
pr_reg.fs_base = regs["fs_base"]
|
||||
pr_reg.gs_base = regs["gs_base"]
|
||||
pr_reg.ds = regs["ds"]
|
||||
pr_reg.es = regs["es"]
|
||||
pr_reg.fs = regs["fs"]
|
||||
pr_reg.gs = regs["gs"]
|
||||
|
||||
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"]
|
||||
regs = self._get_fpregs(core)
|
||||
|
||||
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"])
|
||||
self._set_fpregset(fpregset, regs)
|
||||
|
||||
nhdr = elf.Elf64_Nhdr()
|
||||
nhdr.n_namesz = 5
|
||||
|
|
@ -420,6 +443,58 @@ class coredump_generator:
|
|||
|
||||
return note
|
||||
|
||||
def _get_fpregs(self, core):
|
||||
"""
|
||||
Get the floating point register dictionary based on the current architecture.
|
||||
"""
|
||||
fpregs_key_dict = {"aarch64": "fpsimd", "x86_64": "fpregs"}
|
||||
fpregs_key = fpregs_key_dict[self.machine]
|
||||
|
||||
thread_info_key = self.thread_info_key[self.machine]
|
||||
|
||||
return core[thread_info_key][fpregs_key]
|
||||
|
||||
def _set_fpregset(self, fpregset, regs):
|
||||
"""
|
||||
Set the fpregset struct based on the current architecture.
|
||||
"""
|
||||
if self.machine == "aarch64":
|
||||
fpregset.vregs = (ctypes.c_ulonglong * len(regs["vregs"]))(*regs["vregs"])
|
||||
fpregset.fpsr = regs["fpsr"]
|
||||
fpregset.fpcr = regs["fpcr"]
|
||||
elif self.machine == "x86_64":
|
||||
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"])
|
||||
|
||||
def _gen_arm_tls(self, tid):
|
||||
"""
|
||||
Generate NT_ARM_TLS note for thread tid of process pid.
|
||||
"""
|
||||
core = self.cores[tid]
|
||||
tls = ctypes.c_ulonglong(core["ti_aarch64"]["tls"])
|
||||
|
||||
nhdr = elf.Elf64_Nhdr()
|
||||
nhdr.n_namesz = 6
|
||||
nhdr.n_descsz = ctypes.sizeof(ctypes.c_ulonglong)
|
||||
nhdr.n_type = elf.NT_ARM_TLS
|
||||
|
||||
note = elf_note()
|
||||
note.data = tls
|
||||
note.owner = b"LINUX"
|
||||
note.nhdr = nhdr
|
||||
|
||||
return note
|
||||
|
||||
def _gen_x86_xstate(self, pid, tid):
|
||||
"""
|
||||
Generate NT_X86_XSTATE note for thread tid of process pid.
|
||||
|
|
@ -593,8 +668,11 @@ class coredump_generator:
|
|||
|
||||
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))
|
||||
if self.machine == "aarch64":
|
||||
notes.append(self._gen_arm_tls(tid))
|
||||
elif self.machine == "x86_64":
|
||||
notes.append(self._gen_x86_xstate(pid, tid))
|
||||
|
||||
return notes
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
# Define structures and constants for generating elf file.
|
||||
import ctypes
|
||||
import platform
|
||||
|
||||
MACHINE = platform.machine()
|
||||
|
||||
Elf64_Half = ctypes.c_uint16 # typedef uint16_t Elf64_Half;
|
||||
Elf64_Word = ctypes.c_uint32 # typedef uint32_t Elf64_Word;
|
||||
|
|
@ -39,6 +42,7 @@ 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 */
|
||||
EM_AARCH64 = 183 # #define EM_AARCH64 183 /* ARM AARCH64 */
|
||||
|
||||
# Legal values for e_version (version).
|
||||
EV_CURRENT = 1 # #define EV_CURRENT 1 /* Current version */
|
||||
|
|
@ -119,6 +123,7 @@ 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 */
|
||||
NT_ARM_TLS = 0x401 # #define NT_ARM_TLS 0x401 /* ARM TLS register */
|
||||
|
||||
|
||||
class Elf64_Nhdr(ctypes.Structure): # typedef struct
|
||||
|
|
@ -218,7 +223,7 @@ class timeval(ctypes.Structure): # struct timeval
|
|||
]
|
||||
|
||||
|
||||
class user_regs_struct(ctypes.Structure): # struct user_regs_struct
|
||||
class x86_64_user_regs_struct(ctypes.Structure): # struct x86_64_user_regs_struct
|
||||
_fields_ = [
|
||||
("r15",
|
||||
ctypes.c_ulonglong), # __extension__ unsigned long long int r15;
|
||||
|
|
@ -277,10 +282,31 @@ class user_regs_struct(ctypes.Structure): # struct user_regs_struct
|
|||
]
|
||||
|
||||
|
||||
class aarch64_user_regs_struct(ctypes.Structure): # struct aarch64_user_regs_struct
|
||||
_fields_ = [
|
||||
("regs",
|
||||
ctypes.c_ulonglong * 31), # unsigned long long int regs[31];
|
||||
("sp",
|
||||
ctypes.c_ulonglong), # unsigned long long int sp;
|
||||
("pc",
|
||||
ctypes.c_ulonglong), # unsigned long long int pc;
|
||||
("pstate",
|
||||
ctypes.c_ulonglong), # unsigned long long int pstate;
|
||||
]
|
||||
|
||||
|
||||
# elf_greg_t = ctypes.c_ulonglong
|
||||
# ELF_NGREG = ctypes.sizeof(user_regs_struct)/ctypes.sizeof(elf_greg_t)
|
||||
# elf_gregset_t = elf_greg_t*ELF_NGREG
|
||||
elf_gregset_t = user_regs_struct
|
||||
user_regs_dict = {
|
||||
"aarch64": aarch64_user_regs_struct,
|
||||
"x86_64": x86_64_user_regs_struct,
|
||||
}
|
||||
|
||||
try:
|
||||
elf_gregset_t = user_regs_dict[MACHINE]
|
||||
except KeyError:
|
||||
raise ValueError("Current architecture %s is not supported." % MACHINE)
|
||||
|
||||
|
||||
class elf_prstatus(ctypes.Structure): # struct elf_prstatus
|
||||
|
|
@ -420,7 +446,7 @@ class elf_prpsinfo(ctypes.Structure): # struct elf_prpsinfo
|
|||
]
|
||||
|
||||
|
||||
class user_fpregs_struct(ctypes.Structure): # struct user_fpregs_struct
|
||||
class x86_64_user_fpregs_struct(ctypes.Structure): # struct x86_64_user_fpregs_struct
|
||||
_fields_ = [
|
||||
# unsigned short int cwd;
|
||||
("cwd", ctypes.c_ushort),
|
||||
|
|
@ -447,7 +473,28 @@ class user_fpregs_struct(ctypes.Structure): # struct user_fpregs_struct
|
|||
]
|
||||
|
||||
|
||||
elf_fpregset_t = user_fpregs_struct
|
||||
class aarch64_user_fpregs_struct(ctypes.Structure): # struct aarch64_user_fpregs_struct
|
||||
_fields_ = [
|
||||
# unsigned long long int vregs[64];
|
||||
("vregs", ctypes.c_ulonglong * 64),
|
||||
# unsigned int fpsr;
|
||||
("fpsr", ctypes.c_uint),
|
||||
# unsigned int fpcr;
|
||||
("fpcr", ctypes.c_uint),
|
||||
# unsigned int padding[2];
|
||||
("padding", ctypes.c_uint * 2),
|
||||
]
|
||||
|
||||
|
||||
user_fpregs_dict = {
|
||||
"aarch64": aarch64_user_fpregs_struct,
|
||||
"x86_64": x86_64_user_fpregs_struct,
|
||||
}
|
||||
|
||||
try:
|
||||
elf_fpregset_t = user_fpregs_dict[MACHINE]
|
||||
except KeyError:
|
||||
raise ValueError("Current architecture %s is not supported." % MACHINE)
|
||||
|
||||
# siginfo_t related constants.
|
||||
|
||||
|
|
|
|||
|
|
@ -45,9 +45,8 @@ function run_test {
|
|||
|
||||
UNAME_M=$(uname -m)
|
||||
|
||||
if [ "$UNAME_M" != "x86_64" ]; then
|
||||
# the criu-coredump script is only x86_64 aware
|
||||
echo "criu-coredump only support x86_64. skipping."
|
||||
if [[ "$UNAME_M" != "aarch64" && "$UNAME_M" != "x86_64" ]]; then
|
||||
echo "criu-coredump only supports aarch64 and x86_64. skipping."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue