From: Rabin Vincent <rabinv@xxxxxxxx> 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@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility