From d6c2c0d70cf38b66de3448436446f1a12f986bf2 Mon Sep 17 00:00:00 2001 From: Wei Shu Date: Thu, 16 Oct 2014 21:28:55 +0800 Subject: [PATCH] gcore: add ARM64 compat mode support Signed-off-by: Wei Shu --- extensions/libgcore/gcore_arm64.c | 119 +++++++++++++++++++++++++++++++++ extensions/libgcore/gcore_compat_arm.h | 43 ++++++++++++ extensions/libgcore/gcore_defs.h | 33 ++++++++- 3 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 extensions/libgcore/gcore_compat_arm.h diff --git a/extensions/libgcore/gcore_arm64.c b/extensions/libgcore/gcore_arm64.c index 8ea1994..3257389 100755 --- a/extensions/libgcore/gcore_arm64.c +++ b/extensions/libgcore/gcore_arm64.c @@ -102,14 +102,133 @@ static const struct user_regset_view arm64_regset_view = { .e_machine = EM_AARCH64, }; +#ifdef GCORE_ARCH_COMPAT +enum compat_regset { + REGSET_COMPAT_GPR, + REGSET_COMPAT_VFP, +}; + +struct pt_regs { + struct user_pt_regs user_regs; + unsigned long orig_x0; + unsigned long syscallno; +}; + +static int compat_gpr_get(struct task_context *target, + const struct user_regset *regset, + unsigned int size, void *buf) +{ + struct pt_regs pt_regs; + struct user_regs_struct32 *regs = (struct user_regs_struct32 *)buf; + + BZERO(&pt_regs, sizeof(pt_regs)); + BZERO(regs, sizeof(*regs)); + + readmem(machdep->get_stacktop(target->task) - 16 - SIZE(pt_regs), KVADDR, + &pt_regs, sizeof(struct pt_regs), "compat_gpr_get: pt_regs", + gcore_verbose_error_handle()); + + regs->r0 = pt_regs.user_regs.regs[0]; + regs->r1 = pt_regs.user_regs.regs[1]; + regs->r2 = pt_regs.user_regs.regs[2]; + regs->r3 = pt_regs.user_regs.regs[3]; + regs->r4 = pt_regs.user_regs.regs[4]; + regs->r5 = pt_regs.user_regs.regs[5]; + regs->r6 = pt_regs.user_regs.regs[6]; + regs->r7 = pt_regs.user_regs.regs[7]; + regs->r8 = pt_regs.user_regs.regs[8]; + regs->r9 = pt_regs.user_regs.regs[9]; + regs->r10 = pt_regs.user_regs.regs[10]; + regs->fp = pt_regs.user_regs.regs[11]; + regs->ip = pt_regs.user_regs.regs[12]; + regs->sp = pt_regs.user_regs.regs[13]; + regs->lr = pt_regs.user_regs.regs[14]; + regs->pc = pt_regs.user_regs.pc; + regs->cpsr = pt_regs.user_regs.pstate; + regs->ORIG_r0 = pt_regs.orig_x0; + + return 0; +} + +static int compat_vfp_get(struct task_context *target, + const struct user_regset *regset, + unsigned int size, void *buf) +{ + /* + * The VFP registers are packed into the fpsimd_state, so they all sit + * nicely together for us. We just need to create the fpscr separately. + */ + struct user_fpsimd_state *fpr = (struct user_fpsimd_state *)buf; + compat_ulong_t fpscr; + + BZERO(fpr, sizeof(*fpr)); + readmem(target->task + OFFSET(task_struct_thread) + + GCORE_OFFSET(thread_struct_fpsimd_state), + KVADDR, fpr, sizeof(struct user_fpsimd_state), + "compat_fpr_get: user_fpsimd_state", + gcore_verbose_error_handle()); + + fpscr = (fpr->fpsr & VFP_FPSCR_STAT_MASK) | + (fpr->fpcr & VFP_FPSCR_CTRL_MASK); + + fpr->fpcr = fpscr; + + return 0; +} + +#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ +static const struct user_regset aarch32_regsets[] = { + [REGSET_COMPAT_GPR] = { + .core_note_type = NT_PRSTATUS, + .name = "CORE", + .size = sizeof(struct user_regs_struct32), + .get = compat_gpr_get, + }, + [REGSET_COMPAT_VFP] = { + .core_note_type = NT_ARM_VFP, + .name = "CORE", + .size = VFP_STATE_SIZE, + .get = compat_vfp_get, + }, +}; + +static const struct user_regset_view aarch32_regset_view = { + .name = "aarch32", + .e_machine = EM_ARM, + .regsets = aarch32_regsets, + .n = ARRAY_SIZE(aarch32_regsets) +}; +#endif /* GCORE_ARCH_COMPAT */ + const struct user_regset_view * task_user_regset_view(void) { +#ifdef GCORE_ARCH_COMPAT + if (gcore_is_arch_32bit_emulation(CURRENT_CONTEXT())) + return &aarch32_regset_view; +#endif /* GCORE_ARCH_COMPAT */ return &arm64_regset_view; } +#ifdef GCORE_ARCH_COMPAT +enum gcore_arm64_thread_info_flag +{ + TIF_32BIT = 22 /* 32bit process */ +}; +#endif /* GCORE_ARCH_COMPAT */ + int gcore_is_arch_32bit_emulation(struct task_context *tc) { +#ifdef GCORE_ARCH_COMPAT + uint32_t flags; + char *thread_info_buf; + + thread_info_buf = fill_thread_info(tc->thread_info); + flags = ULONG(thread_info_buf + OFFSET(thread_info_flags)); + + if (flags & (1UL << TIF_32BIT)) + return TRUE; +#endif /* GCORE_ARCH_COMPAT */ return FALSE; } diff --git a/extensions/libgcore/gcore_compat_arm.h b/extensions/libgcore/gcore_compat_arm.h new file mode 100644 index 0000000..bec9c56 --- /dev/null +++ b/extensions/libgcore/gcore_compat_arm.h @@ -0,0 +1,43 @@ +/* gcore_compat_arm.h -- core analysis suite + * + * Copyright (C) 2014 Marvell. Inc + * author: Wei Shu + * + * 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. + */ +#ifndef GCORE_COMPAT_ARM_H_ +#define GCORE_COMPAT_ARM_H_ +#include + +typedef int32_t compat_time_t; +typedef int32_t compat_pid_t; +typedef uint32_t __compat_uid_t; +typedef uint32_t __compat_gid_t; +typedef int32_t compat_int_t; +typedef uint32_t compat_ulong_t; + +struct compat_timeval { + compat_time_t tv_sec; + int32_t tv_usec; +}; + +typedef struct user_regs_struct32 compat_elf_gregset_t; + +/* Masks for extracting the FPSR and FPCR from the FPSCR */ +#define VFP_FPSCR_STAT_MASK 0xf800009f +#define VFP_FPSCR_CTRL_MASK 0x07f79f00 +/* + * The VFP state has 32x64-bit registers and a single 32-bit + * control/status register. + */ +#define VFP_STATE_SIZE ((32 * 8) + 4) + +#endif /* GCORE_COMPAT_ARM_H_ */ diff --git a/extensions/libgcore/gcore_defs.h b/extensions/libgcore/gcore_defs.h index 95b256d..058340e 100755 --- a/extensions/libgcore/gcore_defs.h +++ b/extensions/libgcore/gcore_defs.h @@ -18,7 +18,7 @@ #include #include -#ifdef X86_64 +#if defined(X86_64) || defined(ARM64) #define GCORE_ARCH_COMPAT 1 #endif @@ -26,6 +26,10 @@ #include #endif +#ifdef ARM64 +#include +#endif + #define PN_XNUM 0xffff #define ELF_CORE_EFLAGS 0 @@ -109,7 +113,7 @@ #define Elf_Shdr Elf64_Shdr #define Elf_Nhdr Elf64_Nhdr -#ifndef NT_ARM_TLS +#ifndef NT_ARM_TLS #define NT_ARM_TLS 0x401 /* ARM TLS register */ #endif #endif @@ -410,7 +414,6 @@ struct user_regs_struct { unsigned long fs; unsigned long gs; }; -#endif struct user_regs_struct32 { uint32_t ebx, ecx, edx, esi, edi, ebp, eax; @@ -421,6 +424,7 @@ struct user_regs_struct32 { uint32_t eflags, esp; unsigned short ss, __ss; }; +#endif #ifdef X86 struct user_regs_struct { @@ -532,6 +536,29 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; /* Register set for the floating-point registers. */ typedef struct user_fpsimd_state elf_fpregset_t; +#ifdef GCORE_ARCH_COMPAT +/* AArch32 registers. */ +struct user_regs_struct32{ + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t fp; + uint32_t ip; + uint32_t sp; + uint32_t lr; + uint32_t pc; + uint32_t cpsr; + uint32_t ORIG_r0; +}; +#endif /* GCORE_ARCH_COMPAT */ #endif #if defined(X86) || defined(X86_64) || defined(ARM) -- 1.9.1