

--- crash-gcore-command-1.2.2/gcore.mk.orig
+++ crash-gcore-command-1.2.2/gcore.mk
@@ -36,6 +36,12 @@ ifeq ($(shell arch), arm)
   ARCH=SUPPORTED
 endif
 
+ifeq ($(shell arch), aarch64)
+  TARGET=ARM64
+  TARGET_CFLAGS=
+  ARCH=SUPPORTED
+endif
+
 ifeq ($(shell /bin/ls /usr/include/crash/defs.h 2>/dev/null), /usr/include/crash/defs.h)
   INCDIR=/usr/include/crash
 endif
@@ -63,6 +69,10 @@ ifneq (,$(findstring $(TARGET), ARM))
 GCORE_CFILES += libgcore/gcore_arm.c
 endif
 
+ifneq (,$(findstring $(TARGET), ARM64))
+GCORE_CFILES += libgcore/gcore_arm64.c
+endif
+
 GCORE_OFILES = $(patsubst %.c,%.o,$(GCORE_CFILES))
 
 COMMON_CFLAGS=-Wall -I$(INCDIR) -I./libgcore -fPIC -D$(TARGET) \


--- crash-gcore-command-1.2.2/gcore.c.orig
+++ crash-gcore-command-1.2.2/gcore.c
@@ -181,8 +181,8 @@ NULL,
 void
 cmd_gcore(void)
 {
-	char c, *foptarg, *voptarg;
-	int optversion;
+	char *foptarg, *voptarg;
+	int c, optversion;
 
 	if (ACTIVE())
 		error(FATAL, "no support on live kernel\n");
@@ -364,6 +364,8 @@ static void gcore_offset_table_init(void
 	if (GCORE_INVALID_MEMBER(inode_i_nlink))
 		GCORE_ANON_MEMBER_OFFSET_INIT(inode_i_nlink, "inode", "i_nlink");
 	GCORE_MEMBER_OFFSET_INIT(nsproxy_pid_ns, "nsproxy", "pid_ns");
+	if (GCORE_INVALID_MEMBER(nsproxy_pid_ns))
+		GCORE_MEMBER_OFFSET_INIT(nsproxy_pid_ns, "nsproxy", "pid_ns_for_children");
 	GCORE_MEMBER_OFFSET_INIT(mm_context_t_vdso, "mm_context_t", "vdso");
 	GCORE_MEMBER_OFFSET_INIT(mm_struct_arg_start, "mm_struct", "arg_start");
 	GCORE_MEMBER_OFFSET_INIT(mm_struct_arg_end, "mm_struct", "arg_end");
@@ -486,6 +488,8 @@ static void gcore_offset_table_init(void
 	GCORE_MEMBER_OFFSET_INIT(vfp_state_hard, "vfp_state", "hard");
 	GCORE_MEMBER_OFFSET_INIT(vfp_hard_struct_fpregs, "vfp_hard_struct", "fpregs");
 	GCORE_MEMBER_OFFSET_INIT(vfp_hard_struct_fpscr, "vfp_hard_struct", "fpscr");
+	GCORE_MEMBER_OFFSET_INIT(thread_struct_fpsimd_state, "thread_struct", "fpsimd_state");
+	GCORE_MEMBER_OFFSET_INIT(thread_struct_tp_value, "thread_struct", "tp_value");
 }
 
 static void gcore_size_table_init(void)


--- crash-gcore-command-1.2.2/libgcore/gcore_defs.h.orig
+++ crash-gcore-command-1.2.2/libgcore/gcore_defs.h
@@ -90,6 +90,26 @@
 #define Elf_Nhdr Elf32_Nhdr
 #endif
 
+#ifdef ARM64
+#define ELF_EXEC_PAGESIZE 4096
+
+#define ELF_MACHINE EM_AARCH64
+#define ELF_OSABI ELFOSABI_NONE
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_AARCH64
+
+#define Elf_Half Elf64_Half
+#define Elf_Word Elf64_Word
+#define Elf_Off Elf64_Off
+
+#define Elf_Ehdr Elf64_Ehdr
+#define Elf_Phdr Elf64_Phdr
+#define Elf_Shdr Elf64_Shdr
+#define Elf_Nhdr Elf64_Nhdr
+#endif
+
 #define PAGE_ALIGN(X) roundup(X, ELF_EXEC_PAGESIZE)
 
 /*
@@ -229,6 +249,11 @@ extern void gcore_default_regsets_init(v
 #define REGSET_VIEW_MACHINE EM_ARM
 #endif
 
+#ifdef ARM64
+#define REGSET_VIEW_NAME "aarch64"
+#define REGSET_VIEW_MACHINE EM_AARCH64
+#endif
+
 extern int gcore_arch_get_fp_valid(struct task_context *tc);
 
 /*
@@ -462,12 +487,17 @@ struct user_regs_struct{
 #endif
 
 typedef ulong elf_greg_t;
+#if defined(X86) || defined(X86_64) || defined(ARM)
 #define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
+#endif
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
 #if defined(X86) || defined(ARM)
 #define PAGE_SIZE 4096
 #endif
+#ifdef ARM64
+#define PAGE_SIZE PAGESIZE()
+#endif
 
 extern int gcore_is_arch_32bit_emulation(struct task_context *tc);
 extern ulong gcore_arch_get_gate_vma(void);
@@ -504,12 +534,14 @@ enum pid_type
         PIDTYPE_MAX
 };
 
+#if defined(X86) || defined(X86_64) || defined(ARM)
 struct elf_siginfo
 {
         int     si_signo;                       /* signal number */
 	int     si_code;                        /* extra code */
         int     si_errno;                       /* errno */
 };
+#endif
 
 /* Parameters used to convert the timespec values: */
 #define NSEC_PER_USEC   1000L
@@ -601,6 +633,7 @@ cputime_to_compat_timeval(const cputime_
 }
 #endif
 
+#if defined(X86) || defined(X86_64) || defined(ARM)
 struct elf_prstatus
 {
 	struct elf_siginfo pr_info;	/* Info associated with signal */
@@ -618,9 +651,12 @@ struct elf_prstatus
 	elf_gregset_t pr_reg;	/* GP registers */
 	int pr_fpvalid;		/* True if math co-processor being used.  */
 };
+#endif
 
+#if defined(X86) || defined(X86_64) || defined(ARM)
 typedef unsigned short __kernel_old_uid_t;
 typedef unsigned short __kernel_old_gid_t;
+#endif
 
 typedef __kernel_old_uid_t      old_uid_t;
 typedef __kernel_old_gid_t      old_gid_t;
@@ -688,6 +724,7 @@ static inline ulong ffz(ulong word)
 
 #define ELF_PRARGSZ     (80)    /* Number of chars for args */
 
+#if defined(X86) || defined(X86_64) || defined(ARM)
 struct elf_prpsinfo
 {
         char    pr_state;       /* numeric process state */
@@ -702,6 +739,7 @@ struct elf_prpsinfo
         char    pr_fname[16];   /* filename of executable */
         char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
 };
+#endif
 
 #ifdef GCORE_ARCH_COMPAT
 
@@ -902,6 +940,8 @@ struct gcore_offset_table
 	long thread_struct_xstate;
 	long thread_struct_io_bitmap_max;
 	long thread_struct_io_bitmap_ptr;
+	long thread_struct_fpsimd_state;
+	long thread_struct_tp_value;
 	long user_regset_n;
 	long vfp_state_hard;
 	long vfp_hard_struct_fpregs;


--- crash-gcore-command-1.2.2/libgcore/gcore_coredump.c.orig
+++ crash-gcore-command-1.2.2/libgcore/gcore_coredump.c
@@ -682,7 +682,12 @@ fill_prstatus_note(struct elf_note_info
 		   struct memelfnote *memnote)
 {
 	struct elf_prstatus dummy, *prstatus = (struct elf_prstatus *)memnote->data;
+#if defined(X86) || defined(X86_64) || defined(ARM)
 	struct user_regs_struct *regs = (struct user_regs_struct *)memnote->data;
+#endif
+#ifdef ARM64
+	struct user_pt_regs *regs = (struct user_pt_regs *)memnote->data;
+#endif
 	ulong pending_signal_sig0, blocked_sig0, real_parent, group_leader,
 		signal, cutime,	cstime;
 


--- /dev/null
+++ crash-gcore-command-1.2.2/libgcore/gcore_arm64.c
@@ -0,0 +1,131 @@
+/* gcore_arm64.c
+ *
+ * Copyright (C) 2014 Red Hat, Inc. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifdef ARM64
+
+#include "defs.h"
+#include <gcore_defs.h>
+#include <stdint.h>
+#include <elf.h>
+
+static int gpr_get(struct task_context *target,
+		   const struct user_regset *regset,
+		   unsigned int size, void *buf)
+{
+	struct user_pt_regs *regs = (struct user_pt_regs *)buf;
+
+	BZERO(regs, sizeof(*regs));
+
+	readmem(machdep->get_stacktop(target->task) - 16 - SIZE(pt_regs), KVADDR,
+		regs, sizeof(struct user_pt_regs), "gpr_get: user_pt_regs",
+		gcore_verbose_error_handle());
+
+	return 0;
+}
+
+static int fpr_get(struct task_context *target,
+		   const struct user_regset *regset,
+		   unsigned int size, void *buf)
+{
+	struct user_fpsimd_state *fpr = (struct user_fpsimd_state *)buf;
+
+	BZERO(fpr, sizeof(*fpr));
+	readmem(target->task + OFFSET(task_struct_thread)
+		+ GCORE_OFFSET(thread_struct_fpsimd_state),
+		KVADDR, fpr, sizeof(struct user_fpsimd_state),
+		"fpr_get: user_fpsimd_state",
+		gcore_verbose_error_handle());
+	return 0;
+}
+
+static int tls_get(struct task_context *target,
+		   const struct user_regset *regset,
+		   unsigned int size, void *buf)
+{
+	void *tls = (void *)buf;
+
+	BZERO(tls, size);
+	readmem(target->task + OFFSET(task_struct_thread)
+		+ GCORE_OFFSET(thread_struct_tp_value),
+		KVADDR, tls, sizeof(void *),
+		"tls_get: tp_value",
+		gcore_verbose_error_handle());
+	return 0;
+}
+
+enum gcore_regset {
+	REGSET_GPR,
+	REGSET_FPR,
+	REGSET_TLS,
+};
+
+static struct user_regset arm64_regsets[] = {
+	[REGSET_GPR] = {
+		.core_note_type = NT_PRSTATUS,
+		.name = "CORE",
+		.size = sizeof(struct elf_prstatus),
+		.get = gpr_get,
+	},
+	[REGSET_FPR] = {
+		.core_note_type = NT_FPREGSET,
+		.name = "CORE",
+		.size = sizeof(struct user_fpsimd_state),
+		.get = fpr_get,
+	},
+	[REGSET_TLS] = {
+		.core_note_type = NT_ARM_TLS,
+		.name = "CORE",
+		.size = sizeof(void *),
+		.get = tls_get,
+	},
+};
+#ifndef ARRAY_SIZE
+#  define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+static const struct user_regset_view arm64_regset_view = {
+	.name = "arm64",
+	.regsets = arm64_regsets,
+	.n = ARRAY_SIZE(arm64_regsets),
+	.e_machine = EM_AARCH64,
+};
+
+const struct user_regset_view *
+task_user_regset_view(void)
+{
+	return &arm64_regset_view;
+}
+
+int gcore_is_arch_32bit_emulation(struct task_context *tc)
+{
+	return FALSE;
+}
+
+ulong gcore_arch_get_gate_vma(void)
+{
+	return 0UL;
+}
+
+char *gcore_arch_vma_name(ulong vma)
+{
+	return NULL;
+}
+
+int gcore_arch_vsyscall_has_vm_alwaysdump_flag(void)
+{
+	return FALSE;
+}
+
+#endif
