[Crash-utility] [PATCH] gcore: Add MIPS support
Dave Anderson
anderson at redhat.com
Tue Dec 27 13:34:31 UTC 2016
Hi Rabin,
I forwarded your post directly to Daisuke Hatayama for review.
Thanks,
Dave
----- Original Message -----
> From: Rabin Vincent <rabinv at axis.com>
>
> This adds basic support for MIPS to the gcore extension.
> ---
> gcore.mk | 10 +++
> libgcore/gcore_coredump.c | 2 +-
> libgcore/gcore_defs.h | 39 ++++++++++--
> libgcore/gcore_mips.c | 159
> ++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 205 insertions(+), 5 deletions(-)
> create mode 100644 libgcore/gcore_mips.c
>
> diff --git a/gcore.mk b/gcore.mk
> index c9683d4..ffc9ce7 100644
> --- a/gcore.mk
> +++ b/gcore.mk
> @@ -42,6 +42,12 @@ ifeq ($(shell arch), aarch64)
> ARCH=SUPPORTED
> endif
>
> +ifeq ($(shell arch), mips)
> + TARGET=MIPS
> + TARGET_CFLAGS=
> + ARCH=SUPPORTED
> +endif
> +
> ifeq ($(shell arch), ppc64)
> TARGET=PPC64
> TARGET_CFLAGS=
> @@ -85,6 +91,10 @@ ifneq (,$(findstring $(TARGET), ARM64))
> GCORE_CFILES += libgcore/gcore_arm64.c
> endif
>
> +ifneq (,$(findstring $(TARGET), MIPS))
> +GCORE_CFILES += libgcore/gcore_mips.c
> +endif
> +
> ifneq (,$(findstring $(TARGET), PPC64))
> GCORE_CFILES += libgcore/gcore_ppc64.c
> endif
> diff --git a/libgcore/gcore_coredump.c b/libgcore/gcore_coredump.c
> index 892ddf9..e91f29a 100644
> --- a/libgcore/gcore_coredump.c
> +++ b/libgcore/gcore_coredump.c
> @@ -683,7 +683,7 @@ fill_prstatus_note(struct elf_note_info *info, struct
> task_context *tc,
> struct memelfnote *memnote)
> {
> struct elf_prstatus *prstatus;
> -#if defined(X86) || defined(X86_64) || defined(ARM) || defined(PPC64)
> +#if defined(X86) || defined(X86_64) || defined(ARM) || defined(MIPS) ||
> defined(PPC64)
> struct user_regs_struct *regs = (struct user_regs_struct *)memnote->data;
> #endif
> #ifdef ARM64
> diff --git a/libgcore/gcore_defs.h b/libgcore/gcore_defs.h
> index ba1fde2..6fdb943 100644
> --- a/libgcore/gcore_defs.h
> +++ b/libgcore/gcore_defs.h
> @@ -94,6 +94,26 @@
> #define Elf_Nhdr Elf32_Nhdr
> #endif
>
> +#ifdef MIPS
> +#define ELF_EXEC_PAGESIZE 4096
> +
> +#define ELF_MACHINE EM_MIPS
> +#define ELF_OSABI ELFOSABI_NONE
> +
> +#define ELF_CLASS ELFCLASS32
> +#define ELF_DATA ELFDATA2LSB
> +#define ELF_ARCH EM_MIPS
> +
> +#define Elf_Half Elf32_Half
> +#define Elf_Word Elf32_Word
> +#define Elf_Off Elf32_Off
> +
> +#define Elf_Ehdr Elf32_Ehdr
> +#define Elf_Phdr Elf32_Phdr
> +#define Elf_Shdr Elf32_Shdr
> +#define Elf_Nhdr Elf32_Nhdr
> +#endif
> +
> #ifdef ARM64
> #define ELF_EXEC_PAGESIZE PAGESIZE()
>
> @@ -290,6 +310,11 @@ extern void gcore_default_regsets_init(void);
> #define REGSET_VIEW_MACHINE EM_AARCH64
> #endif
>
> +#ifdef MIPS
> +#define REGSET_VIEW_NAME "mips"
> +#define REGSET_VIEW_MACHINE EM_MIPS
> +#endif
> +
> #ifdef PPC64
> #define REGSET_VIEW_NAME "ppc64"
> #define REGSET_VIEW_MACHINE EM_PPC64
> @@ -594,6 +619,12 @@ struct user_regs_struct32{
> #endif /* GCORE_ARCH_COMPAT */
> #endif
>
> +#ifdef MIPS
> +struct user_regs_struct {
> + unsigned long gregs[45];
> +};
> +#endif
> +
> #ifdef PPC64
> /* taken from asm/ptrace.h */
> struct user_regs_struct {
> @@ -620,13 +651,13 @@ struct user_regs_struct {
> };
> #endif
>
> -#if defined(X86) || defined(X86_64) || defined(ARM)
> +#if defined(X86) || defined(X86_64) || defined(ARM) || defined(MIPS)
> typedef ulong elf_greg_t;
> #define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
> typedef elf_greg_t elf_gregset_t[ELF_NGREG];
> #endif
>
> -#if defined(X86) || defined(ARM)
> +#if defined(X86) || defined(ARM) || defined(MIPS)
> #define PAGE_SIZE 4096
> #endif
> #if defined(ARM64) || defined(PPC64)
> @@ -783,7 +814,7 @@ struct elf_prstatus
> int pr_fpvalid; /* True if math co-processor being used. */
> };
>
> -#if defined(X86) || defined(X86_64) || defined(ARM)
> +#if defined(X86) || defined(X86_64) || defined(ARM) || defined(MIPS)
> typedef unsigned short __kernel_old_uid_t;
> typedef unsigned short __kernel_old_gid_t;
> #endif
> @@ -803,7 +834,7 @@ typedef __kernel_gid_t __kernel_old_gid_t;
> typedef __kernel_old_uid_t old_uid_t;
> typedef __kernel_old_gid_t old_gid_t;
>
> -#if defined(X86) || defined(ARM)
> +#if defined(X86) || defined(ARM) || defined(MIPS)
> typedef unsigned short __kernel_uid_t;
> typedef unsigned short __kernel_gid_t;
> #endif
> diff --git a/libgcore/gcore_mips.c b/libgcore/gcore_mips.c
> new file mode 100644
> index 0000000..be67d51
> --- /dev/null
> +++ b/libgcore/gcore_mips.c
> @@ -0,0 +1,159 @@
> +/* gcore_mips.c -- core analysis suite
> + *
> + * Copyright (C) 2016 Axis Communications
> + *
> + * 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.
> + */
> +#if defined(MIPS)
> +
> +#include "defs.h"
> +#include <gcore_defs.h>
> +#include <stdint.h>
> +#include <elf.h>
> +#include <asm/ldt.h>
> +
> +#define MIPS32_EF_R0 6
> +#define MIPS32_EF_R1 7
> +#define MIPS32_EF_R26 32
> +#define MIPS32_EF_R27 33
> +#define MIPS32_EF_R31 37
> +#define MIPS32_EF_LO 38
> +#define MIPS32_EF_HI 39
> +#define MIPS32_EF_CP0_EPC 40
> +#define MIPS32_EF_CP0_BADVADDR 41
> +#define MIPS32_EF_CP0_STATUS 42
> +#define MIPS32_EF_CP0_CAUSE 43
> +
> +static int gpr_get(struct task_context *target,
> + const struct user_regset *regset,
> + unsigned int size, void *buf)
> +{
> + static int once;
> + struct user_regs_struct *regs = buf;
> + struct mips_pt_regs_main *mains;
> + struct mips_pt_regs_cp0 *cp0;
> + char pt_regs[SIZE(pt_regs)];
> + int i;
> +
> + /*
> + * All registers are saved in thread_info.regs only on certain types of
> + * entries to the kernel (such as abort handling). For other types of
> + * entries (such as system calls), only a subset of the registers are
> + * saved on entry and the rest are saved on the stack according to the
> + * ABI's calling conventions. To always get the full register set we
> + * would have to unwind the stack and find where the registers are by
> + * using DWARF information. We don't have an implementation for this
> + * right now so warn to avoid misleading the user. Only warn since
> + * this function is called multiple times even for a single invocation
> + * of the gcore command.
> + */
> + if (!once) {
> + once = 1;
> + error(WARNING, "WARNING: Current register values may be inaccurate\n");
> + }
> +
> + readmem(machdep->get_stacktop(target->task) - 32 - SIZE(pt_regs),
> + KVADDR, pt_regs, SIZE(pt_regs), "genregs_get: pt_regs",
> + gcore_verbose_error_handle());
> +
> + mains = (struct mips_pt_regs_main *) (pt_regs + OFFSET(pt_regs_regs));
> + cp0 = (struct mips_pt_regs_cp0 *) \
> + (pt_regs + OFFSET(pt_regs_cp0_badvaddr));
> +
> + BZERO(regs, sizeof(*regs));
> +
> + for (i = MIPS32_EF_R1; i <= MIPS32_EF_R31; i++) {
> + /* k0/k1 are copied as zero. */
> + if (i == MIPS32_EF_R26 || i == MIPS32_EF_R27)
> + continue;
> +
> + regs->gregs[i] = mains->regs[i - MIPS32_EF_R0];
> + }
> +
> + regs->gregs[MIPS32_EF_LO] = mains->lo;
> + regs->gregs[MIPS32_EF_HI] = mains->hi;
> + regs->gregs[MIPS32_EF_CP0_EPC] = cp0->cp0_epc;
> + regs->gregs[MIPS32_EF_CP0_BADVADDR] = cp0->cp0_badvaddr;
> + regs->gregs[MIPS32_EF_CP0_STATUS] = mains->cp0_status;
> + regs->gregs[MIPS32_EF_CP0_CAUSE] = cp0->cp0_cause;
> +
> + return 0;
> +}
> +
> +enum gcore_regset {
> + REGSET_GPR,
> +};
> +
> +static struct user_regset mips_regsets[] = {
> + [REGSET_GPR] = {
> + .core_note_type = NT_PRSTATUS,
> + .name = "CORE",
> + .size = ELF_NGREG * sizeof(unsigned int),
> + .get = gpr_get,
> + },
> +};
> +
> +#ifndef ARRAY_SIZE
> +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
> +#endif
> +
> +static const struct user_regset_view mips_regset_view = {
> + .name = "mips",
> + .regsets = mips_regsets,
> + .n = ARRAY_SIZE(mips_regsets),
> + .e_machine = EM_MIPS,
> +};
> +
> +const struct user_regset_view *
> +task_user_regset_view(void)
> +{
> + return &mips_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)
> +{
> + ulong mm, vm_start, vdso;
> +
> + readmem(vma + OFFSET(vm_area_struct_vm_mm), KVADDR, &mm, sizeof(mm),
> + "gcore_arch_vma_name: vma->vm_mm",
> + gcore_verbose_error_handle());
> +
> + readmem(vma + OFFSET(vm_area_struct_vm_start), KVADDR, &vm_start,
> + sizeof(vm_start), "gcore_arch_vma_name: vma->vm_start",
> + gcore_verbose_error_handle());
> +
> + readmem(mm + GCORE_OFFSET(mm_struct_context) +
> + GCORE_OFFSET(mm_context_t_vdso), KVADDR, &vdso,
> + sizeof(vdso), "gcore_arch_vma_name: mm->context.vdso",
> + gcore_verbose_error_handle());
> +
> + if (mm && vm_start == vdso)
> + return "[vdso]";
> +
> + return NULL;
> +}
> +
> +int gcore_arch_vsyscall_has_vm_alwaysdump_flag(void)
> +{
> + return FALSE;
> +}
> +
> +#endif /* defined(MIPS) */
> --
> 2.1.4
>
> --
> Crash-utility mailing list
> Crash-utility at redhat.com
> https://www.redhat.com/mailman/listinfo/crash-utility
>
More information about the Crash-utility
mailing list