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 Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility