From 8f9d05af09c6038c3282779fd98a2e9ad40f56b2 Mon Sep 17 00:00:00 2001
From: Lei Wen <leiwen@marvell.com>
Date: Sun, 12 Feb 2012 14:28:24 +0800
Subject: [PATCH 2/2] libgcore: add arm support

Change-Id: I597c9ff2d788a3196dc3d9944fe5601dbb6eb8cb
Signed-off-by: Lei Wen <leiwen@marvell.com>
---
 extensions/gcore.c               |    7 ++
 extensions/gcore.mk              |   10 +++
 extensions/libgcore/gcore_arm.c  |  146 ++++++++++++++++++++++++++++++++++++++
 extensions/libgcore/gcore_defs.h |   78 ++++++++++++++++++++-
 4 files changed, 239 insertions(+), 2 deletions(-)
 create mode 100644 extensions/libgcore/gcore_arm.c

diff --git a/extensions/gcore.c b/extensions/gcore.c
index f18e4ef..c8e735b 100644
--- a/extensions/gcore.c
+++ b/extensions/gcore.c
@@ -442,6 +442,8 @@ static void gcore_offset_table_init(void)
 	GCORE_MEMBER_OFFSET_INIT(task_struct_uid, "task_struct", "uid");
 	GCORE_MEMBER_OFFSET_INIT(task_struct_used_math, "task_struct", "used_math");
 	GCORE_MEMBER_OFFSET_INIT(thread_info_status, "thread_info", "status");
+	GCORE_MEMBER_OFFSET_INIT(thread_info_fpstate, "thread_info", "fpstate");
+	GCORE_MEMBER_OFFSET_INIT(thread_info_vfpstate, "thread_info", "vfpstate");
 	GCORE_MEMBER_OFFSET_INIT(thread_struct_ds, "thread_struct", "ds");
 	GCORE_MEMBER_OFFSET_INIT(thread_struct_es, "thread_struct", "es");
 	GCORE_MEMBER_OFFSET_INIT(thread_struct_fs, "thread_struct", "fs");
@@ -466,6 +468,9 @@ static void gcore_offset_table_init(void)
 
 	if (symbol_exists("_cpu_pda"))
 		GCORE_MEMBER_OFFSET_INIT(x8664_pda_oldrsp, "x8664_pda", "oldrsp");
+	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");
 }
 
 static void gcore_size_table_init(void)
@@ -481,6 +486,8 @@ static void gcore_size_table_init(void)
 	GCORE_MEMBER_SIZE_INIT(thread_struct_tls_array, "thread_struct", "tls_array");
 	GCORE_STRUCT_SIZE_INIT(thread_xstate, "thread_xstate");
 	GCORE_MEMBER_SIZE_INIT(vm_area_struct_anon_vma, "vm_area_struct", "anon_vma");
+	GCORE_MEMBER_SIZE_INIT(vfp_hard_struct_fpregs, "vfp_hard_struct", "fpregs");
+	GCORE_MEMBER_SIZE_INIT(vfp_hard_struct_fpscr, "vfp_hard_struct", "fpscr");
 
 }
 
diff --git a/extensions/gcore.mk b/extensions/gcore.mk
index ec50227..1eb743a 100644
--- a/extensions/gcore.mk
+++ b/extensions/gcore.mk
@@ -30,6 +30,12 @@ ifeq ($(shell arch), x86_64)
   ARCH=SUPPORTED
 endif
 
+ifeq ($(shell arch), arm)
+  TARGET=ARM
+  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
@@ -53,6 +59,10 @@ ifneq (,$(findstring $(TARGET), X86 X86_64))
 GCORE_CFILES += libgcore/gcore_x86.c
 endif
 
+ifneq (,$(findstring $(TARGET), ARM))
+GCORE_CFILES += libgcore/gcore_arm.c
+endif
+
 GCORE_OFILES = $(patsubst %.c,%.o,$(GCORE_CFILES))
 
 COMMON_CFLAGS=-Wall -I$(INCDIR) -I./libgcore -fPIC -D$(TARGET) \
diff --git a/extensions/libgcore/gcore_arm.c b/extensions/libgcore/gcore_arm.c
new file mode 100644
index 0000000..dd21db3
--- /dev/null
+++ b/extensions/libgcore/gcore_arm.c
@@ -0,0 +1,146 @@
+/* gcore_arm.c -- core analysis suite
+ *
+ * Copyright (C) 2012 Marvell INC
+ * Author: Lei Wen <leiwen@marvell.com>
+ *
+ * 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(ARM)
+
+#include "defs.h"
+#include <gcore_defs.h>
+#include <stdint.h>
+#include <elf.h>
+#include <asm/ldt.h>
+
+static int gpr_get(struct task_context *target,
+		       const struct user_regset *regset,
+		       unsigned int size, void *buf)
+{
+	struct user_regs_struct *regs = (struct user_regs_struct *)buf;
+
+	BZERO(regs, sizeof(*regs));
+
+	readmem(machdep->get_stacktop(target->task) - 8 - SIZE(pt_regs), KVADDR,
+		regs, SIZE(pt_regs), "genregs_get: pt_regs",
+		gcore_verbose_error_handle());
+
+	return 0;
+}
+
+static int fpa_get(struct task_context *target,
+		       const struct user_regset *regset,
+		       unsigned int size, void *buf)
+{
+	struct user_fp *fp = (struct user_fp*)buf;
+
+	BZERO(fp, sizeof(*fp));
+	readmem(target->task + OFFSET(task_struct_thread_info)
+		+ GCORE_OFFSET(thread_info_fpstate),
+		KVADDR, fp, sizeof(*fp),
+		"fpa_get: fpstate",
+		gcore_verbose_error_handle());
+	return 0;
+}
+
+static int vfp_get(struct task_context *target,
+		       const struct user_regset *regset,
+		       unsigned int size, void *buf)
+{
+	struct user_vfp *vfp = (struct user_vfp*)buf;
+
+	BZERO(vfp, sizeof(*vfp));
+	readmem(target->task + OFFSET(task_struct_thread_info)
+		+ GCORE_OFFSET(thread_info_vfpstate)
+		+ GCORE_OFFSET(vfp_state_hard)
+		+ GCORE_OFFSET(vfp_hard_struct_fpregs),
+		KVADDR, &vfp->fpregs, GCORE_SIZE(vfp_hard_struct_fpregs),
+		"vfp_get: fpregs",
+		gcore_verbose_error_handle());
+
+	readmem(target->task + OFFSET(task_struct_thread_info)
+		+ GCORE_OFFSET(thread_info_vfpstate)
+		+ GCORE_OFFSET(vfp_state_hard)
+		+ GCORE_OFFSET(vfp_hard_struct_fpscr),
+		KVADDR, &vfp->fpscr, GCORE_SIZE(vfp_hard_struct_fpscr),
+		"vfp_get: fpregs",
+		gcore_verbose_error_handle());
+	return TRUE;
+}
+
+static inline int
+vfp_vector_active(struct task_context *target,
+		  const struct user_regset *regset)
+{
+	return !!symbol_exists("vfp_vector");
+}
+
+enum gcore_regset {
+	REGSET_GPR,
+	REGSET_FPR,
+	REGSET_VFP,
+};
+
+#define NT_ARM_VFP	0x400           /* ARM VFP/NEON registers */
+static struct user_regset arm_regsets[] = {
+	[REGSET_GPR] = {
+		.core_note_type = NT_PRSTATUS,
+		.name = "CORE",
+		.size = ELF_NGREG * sizeof(unsigned int),
+		.get = gpr_get,
+	},
+	[REGSET_FPR] = {
+		.core_note_type = NT_FPREGSET,
+		.name = "CORE",
+		.size = sizeof(struct user_fp),
+		.get = fpa_get,
+	},
+	[REGSET_VFP] = {
+		.core_note_type = NT_ARM_VFP,
+		.size = ARM_VFPREGS_SIZE,
+		.active = vfp_vector_active,
+		.get = vfp_get,
+	},
+};
+#ifndef ARRAY_SIZE
+#  define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+static const struct user_regset_view arm_regset_view = {
+	.name = "arm",
+	.regsets = arm_regsets,
+	.n = ARRAY_SIZE(arm_regsets),
+	.e_machine = EM_ARM,
+};
+
+const struct user_regset_view *
+task_user_regset_view(void)
+{
+	return &arm_regset_view;
+}
+
+int gcore_is_arch_32bit_emulation(struct task_context *tc)
+{
+	return FALSE;
+}
+
+/**
+ * Return an address to gate_vma.
+ */
+ulong gcore_arch_get_gate_vma(void)
+{
+	if (!symbol_exists("gate_vma"))
+		return 0UL;
+
+	return symbol_value("gate_vma");
+}
+
+#endif /* defined(ARM) */
diff --git a/extensions/libgcore/gcore_defs.h b/extensions/libgcore/gcore_defs.h
index 1c4969d..1c44096 100644
--- a/extensions/libgcore/gcore_defs.h
+++ b/extensions/libgcore/gcore_defs.h
@@ -65,6 +65,24 @@
 #define Elf_Phdr Elf32_Phdr
 #define Elf_Shdr Elf32_Shdr
 #define Elf_Nhdr Elf32_Nhdr
+#elif ARM
+#define ELF_EXEC_PAGESIZE 4096
+
+#define ELF_MACHINE EM_ARM
+#define ELF_OSABI ELFOSABI_NONE
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_ARM
+
+#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
 
 /*
@@ -209,6 +227,9 @@ extern void gcore_default_regsets_init(void);
 #elif IA64
 #define REGSET_VIEW_NAME "ia64"
 #define REGSET_VIEW_MACHINE EM_IA_64
+#elif ARM
+#define REGSET_VIEW_NAME "arm"
+#define REGSET_VIEW_MACHINE EM_ARM
 #endif
 
 /*
@@ -393,11 +414,57 @@ struct user_regs_struct {
 };
 #endif
 
+#ifdef ARM
+struct user_fp {
+	struct fp_reg {
+		unsigned int sign1:1;
+		unsigned int unused:15;
+		unsigned int sign2:1;
+		unsigned int exponent:14;
+		unsigned int j:1;
+		unsigned int mantissa1:31;
+		unsigned int mantissa0:32;
+	} fpregs[8];
+	unsigned int fpsr:32;
+	unsigned int fpcr:32;
+	unsigned char ftype[8];
+	unsigned int init_flag;
+};
+
+struct user_vfp {
+	unsigned long long fpregs[32];
+	unsigned long fpscr;
+};
+
+struct user_regs_struct{
+	unsigned long r0;
+	unsigned long r1;
+	unsigned long r2;
+	unsigned long r3;
+	unsigned long r4;
+	unsigned long r5;
+	unsigned long r6;
+	unsigned long r7;
+	unsigned long r8;
+	unsigned long r9;
+	unsigned long r10;
+	unsigned long fp;
+	unsigned long ip;
+	unsigned long sp;
+	unsigned long lr;
+	unsigned long pc;
+	unsigned long cpsr;
+	unsigned long ORIG_r0;
+};
+
+#define ARM_VFPREGS_SIZE ( 32 * 8 /*fpregs*/ + 4 /*fpscr*/ )
+#endif
+
 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];
 
-#ifdef X86
+#if X86 || ARM
 #define PAGE_SIZE 4096
 #endif
 
@@ -557,7 +624,7 @@ typedef __kernel_old_gid_t      old_gid_t;
 #ifdef X86_64
 typedef unsigned int __kernel_uid_t;
 typedef unsigned int __kernel_gid_t;
-#elif X86
+#elif X86 || ARM
 typedef unsigned short __kernel_uid_t;
 typedef unsigned short __kernel_gid_t;
 #endif
@@ -807,6 +874,8 @@ struct gcore_offset_table
 	long task_struct_uid;
 	long task_struct_used_math;
 	long thread_info_status;
+	long thread_info_fpstate;
+	long thread_info_vfpstate;
 	long thread_struct_ds;
 	long thread_struct_es;
 	long thread_struct_fs;
@@ -821,6 +890,9 @@ struct gcore_offset_table
 	long thread_struct_io_bitmap_max;
 	long thread_struct_io_bitmap_ptr;
 	long user_regset_n;
+	long vfp_state_hard;
+	long vfp_hard_struct_fpregs;
+	long vfp_hard_struct_fpscr;
 	long vm_area_struct_anon_vma;
 	long x8664_pda_oldrsp;
 };
@@ -835,6 +907,8 @@ struct gcore_size_table
 	long thread_struct_gs;
 	long thread_struct_gsindex;
 	long thread_struct_tls_array;
+	long vfp_hard_struct_fpregs;
+	long vfp_hard_struct_fpscr;
 	long vm_area_struct_anon_vma;
 	long thread_xstate;
 	long i387_union;
-- 
1.7.5.4

