Hello Daisuke,
Attached is a patch to introduce support for the ARM64 architecture
for the gcore extension module.
The patch is fairly straight-forward other than the fact that on
ARM64 machines, the chain of headers included from the crash utility's
"defs.h" looks like this:
/usr/include/crash/defs.h
/usr/include/signal.h
/usr/include/sys/ucontext.h
/usr/include/sys/procfs.h
The <sys/procfs.h> file defines several of the ELF-related structures that
are hard-coded in gcore_defs.h, causing compile failures due to duplicate
structure declarations.
Note that the <sys/ucontext.h> file on the other three architectures does
not #include <sys/procfs.h> so there are no conflicts. It would be possible
to move all architectures to include <sys/procfs.h>, but for example, that
would also bring in the <sys/user.h> definition of the user_regs_struct,
which in turn causes a myriad of register name mismatches in gcore_x86.c.
So for the sake of simplicity, wherever there is an ARM64-only duplicate
structure or definition in gcore_defs.h, I've encapsulated them by:
#if defined(X86) || defined(X86_64) || defined(ARM)
Also, there are two generic fixes, one where the gcore module fails on
Linux 3.11 and later kernels due to a structure member name change,
and another that changes the getopt() return variable to an "int" instead
of a "char".
Here are the details:
gcore.mk:
- Introduce ARM64 as a supported architecture
- Add libgcore/gcore_arm64 to GCORE_CFILES
gcore.c:
- In cmd_gcore() change "c" type to "int" to correctly match
the return type of getopt(); without it, the while loop
spins indefinitely on ARM64.
- In gcore_offset_table_init(), account for the Linux 3.11
structure member name-change from ns_proxy.pid_ns to
ns_proxy.pid_ns_for_children; without it, the gcore command
fails during initialization.
libgcore/gcore_defs.h:
- Add ARM64 ELF- and REGSET_VIEW-related #defines required for
each architecture.
- Account for variable page sizes in ARM64.
- Restrict the hard-coded ELF_NGREG, elf_siginfo, elf_prstatus,
__kernel_old_uid_t and __kernel_old_gid_t, and elf_prsinfo
definitions to X86, X86_64 and ARM architectures.
- Add ARM64 thread_struct_fpsmid_state and thread_struct_tp_value
offsets to gcore_offset_table.
libgcore/gcore_coredump.c:
- In fill_prstatus_note(), account for the ARM64 usage of
"user_pt_regs" structure instead of the "user_regs_struct"
used by the other architectures.
libgcore/gcore_arm64.c:
- Implement ARM64-specific user_regset and user_regset_view
structures and all required support functions.
Please accept these changes into an new package version.
Thanks,
Dave
--- 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
--
Crash-utility mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility