[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1397824031-4892-22-git-send-email-lftan@altera.com>
Date: Fri, 18 Apr 2014 20:27:08 +0800
From: Ley Foon Tan <lftan@...era.com>
To: <linux-arch@...r.kernel.org>, <linux-kernel@...r.kernel.org>,
<linux-doc@...r.kernel.org>
CC: Ley Foon Tan <lftan@...era.com>, <lftan.linux@...il.com>,
<cltang@...esourcery.com>
Subject: [PATCH 25/28] nios2: ptrace support
Add ptrace support for nios2.
Signed-off-by: Ley Foon Tan <lftan@...era.com>
---
arch/nios2/include/asm/ptrace.h | 40 +++++++
arch/nios2/include/uapi/asm/ptrace.h | 123 ++++++++++++++++++++++
arch/nios2/kernel/ptrace.c | 198 +++++++++++++++++++++++++++++++++++
3 files changed, 361 insertions(+)
create mode 100644 arch/nios2/include/asm/ptrace.h
create mode 100644 arch/nios2/include/uapi/asm/ptrace.h
create mode 100644 arch/nios2/kernel/ptrace.c
diff --git a/arch/nios2/include/asm/ptrace.h b/arch/nios2/include/asm/ptrace.h
new file mode 100644
index 0000000..ca8588ed8c32eff5ed081c21c55fc142bb16f151
--- /dev/null
+++ b/arch/nios2/include/asm/ptrace.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 Altera Corporation
+ * Copyright (C) 2010 Tobias Klauser <tklauser@...tanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ *
+ * based on m68k asm/processor.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_PTRACE_H
+#define _ASM_NIOS2_PTRACE_H
+
+#include <uapi/asm/ptrace.h>
+
+#ifndef __ASSEMBLY__
+
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS 12
+#define PTRACE_SETREGS 13
+
+/*
+ * Supervisor mode
+ */
+
+# define user_mode(regs) (((regs)->estatus & ESTATUS_EU))
+
+
+#define instruction_pointer(regs) ((regs)->ra)
+#define profile_pc(regs) instruction_pointer(regs)
+#define user_stack_pointer(regs) ((regs)->sp)
+extern void show_regs(struct pt_regs *);
+
+#define current_pt_regs() \
+ ((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE)\
+ - 1)
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_NIOS2_PTRACE_H */
diff --git a/arch/nios2/include/uapi/asm/ptrace.h b/arch/nios2/include/uapi/asm/ptrace.h
new file mode 100644
index 0000000..e37ca15350ea60e8eb7f73b5dad331886abb5e31
--- /dev/null
+++ b/arch/nios2/include/uapi/asm/ptrace.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2010 Tobias Klauser <tklauser@...tanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ *
+ * based on m68k asm/processor.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _UAPI_ASM_NIOS2_PTRACE_H
+#define _UAPI_ASM_NIOS2_PTRACE_H
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Register numbers used by 'ptrace' system call interface.
+ */
+
+/* GP registers */
+#define PTR_R0 0
+#define PTR_R1 1
+#define PTR_R2 2
+#define PTR_R3 3
+#define PTR_R4 4
+#define PTR_R5 5
+#define PTR_R6 6
+#define PTR_R7 7
+#define PTR_R8 8
+#define PTR_R9 9
+#define PTR_R10 10
+#define PTR_R11 11
+#define PTR_R12 12
+#define PTR_R13 13
+#define PTR_R14 14
+#define PTR_R15 15
+#define PTR_R16 16
+#define PTR_R17 17
+#define PTR_R18 18
+#define PTR_R19 19
+#define PTR_R20 20
+#define PTR_R21 21
+#define PTR_R22 22
+#define PTR_R23 23
+#define PTR_R24 24
+#define PTR_R25 25
+#define PTR_GP 26
+#define PTR_SP 27
+#define PTR_FP 28
+#define PTR_EA 29
+#define PTR_BA 30
+#define PTR_RA 31
+/* Control registers */
+#define PTR_PC 32
+#define PTR_STATUS 33
+#define PTR_ESTATUS 34
+#define PTR_BSTATUS 35
+#define PTR_IENABLE 36
+#define PTR_IPENDING 37
+#define PTR_CPUID 38
+#define PTR_CTL6 39
+#define PTR_CTL7 40
+#define PTR_PTEADDR 41
+#define PTR_TLBACC 42
+#define PTR_TLBMISC 43
+
+/* Text/data offsets, needed by gdbserver */
+#define PT_TEXT_ADDR (44*4)
+#define PT_TEXT_END_ADDR (45*4)
+#define PT_DATA_ADDR (46*4)
+
+/* this struct defines the way the registers are stored on the
+ stack during a system call.
+
+ There is a fake_regs in setup.c that has to match pt_regs.*/
+
+struct pt_regs {
+ unsigned long r8; /* r8-r15 Caller-saved GP registers */
+ unsigned long r9;
+ unsigned long r10;
+ unsigned long r11;
+ unsigned long r12;
+ unsigned long r13;
+ unsigned long r14;
+ unsigned long r15;
+ unsigned long r1; /* Assembler temporary */
+ unsigned long r2; /* Retval LS 32bits */
+ unsigned long r3; /* Retval MS 32bits */
+ unsigned long r4; /* r4-r7 Register arguments */
+ unsigned long r5;
+ unsigned long r6;
+ unsigned long r7;
+ unsigned long orig_r2; /* Copy of r2 ?? */
+ unsigned long ra; /* Return address */
+ unsigned long fp; /* Frame pointer */
+ unsigned long sp; /* Stack pointer */
+ unsigned long gp; /* Global pointer */
+ unsigned long estatus;
+ unsigned long ea; /* Exception return address (pc) */
+ unsigned long orig_r7;
+};
+
+/*
+ * This is the extended stack used by signal handlers and the context
+ * switcher: it's pushed after the normal "struct pt_regs".
+ */
+struct switch_stack {
+ unsigned long r16; /* r16-r23 Callee-saved GP registers */
+ unsigned long r17;
+ unsigned long r18;
+ unsigned long r19;
+ unsigned long r20;
+ unsigned long r21;
+ unsigned long r22;
+ unsigned long r23;
+ unsigned long fp;
+ unsigned long gp;
+ unsigned long ra;
+};
+
+#endif /* __ASSEMBLY__ */
+#endif /* _UAPI_ASM_NIOS2_PTRACE_H */
diff --git a/arch/nios2/kernel/ptrace.c b/arch/nios2/kernel/ptrace.c
new file mode 100644
index 0000000..5db61796b2c11532dd6219a972331d9c09f5c30a
--- /dev/null
+++ b/arch/nios2/kernel/ptrace.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2010 Tobias Klauser <tklauser@...tanz.ch>
+ *
+ * based on arch/m68knommu/kernel/ptrace.c
+ *
+ * Copyright (C) 1994 by Hamish Macdonald
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#include <linux/uaccess.h>
+
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/* determines which bits in the SR the user has access to. */
+/* 1 = access 0 = no access */
+#define SR_MASK 0x00000000
+
+/* Find the stack offset for a register, relative to thread.ksp. */
+#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
+#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \
+ - sizeof(struct switch_stack))
+
+/* Mapping from PT_xxx to the stack offset at which the register is
+ * saved.
+ */
+static int regoff[] = {
+ -1, PT_REG(r1), PT_REG(r2), PT_REG(r3),
+ PT_REG(r4), PT_REG(r5), PT_REG(r6), PT_REG(r7),
+ PT_REG(r8), PT_REG(r9), PT_REG(r10), PT_REG(r11),
+ PT_REG(r12), PT_REG(r13), PT_REG(r14), PT_REG(r15), /* reg 15 */
+ SW_REG(r16), SW_REG(r17), SW_REG(r18), SW_REG(r19),
+ SW_REG(r20), SW_REG(r21), SW_REG(r22), SW_REG(r23),
+ -1, -1, PT_REG(gp), PT_REG(sp),
+ PT_REG(fp), PT_REG(ea), -1, PT_REG(ra), /* reg 31 */
+ PT_REG(ea), -1, -1, -1, /* use ea for pc */
+ -1, -1, -1, -1,
+ -1, -1, -1, -1 /* reg 43 */
+};
+
+/*
+ * Get contents of register REGNO in task TASK.
+ */
+static inline long get_reg(struct task_struct *task, int regno)
+{
+ unsigned long *addr;
+
+ if (regno >= ARRAY_SIZE(regoff) || regoff[regno] == -1)
+ return 0;
+
+ addr = (unsigned long *)((char *)task->thread.kregs + regoff[regno]);
+ return *addr;
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+static inline int put_reg(struct task_struct *task, int regno,
+ unsigned long data)
+{
+ unsigned long *addr;
+
+ if (regno >= ARRAY_SIZE(regoff) || regoff[regno] == -1)
+ return -1;
+
+ addr = (unsigned long *)((char *)task->thread.kregs + regoff[regno]);
+ *addr = data;
+ return 0;
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Nothing special to do here, no processor debug support.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+}
+
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
+{
+ unsigned long tmp;
+ unsigned int i;
+ int ret;
+
+ switch (request) {
+ /* read the word at location addr in the USER area. */
+ case PTRACE_PEEKUSR:
+ pr_debug("PEEKUSR: addr=0x%08lx\n", addr);
+ ret = -EIO;
+ if (addr & 3)
+ break;
+
+ addr = addr >> 2; /* temporary hack. */
+ ret = -EIO;
+ if (addr < ARRAY_SIZE(regoff))
+ tmp = get_reg(child, addr);
+ else if (addr == PT_TEXT_ADDR / 4)
+ tmp = child->mm->start_code;
+ else if (addr == PT_DATA_ADDR / 4)
+ tmp = child->mm->start_data;
+ else if (addr == PT_TEXT_END_ADDR / 4)
+ tmp = child->mm->end_code;
+ else
+ break;
+ ret = put_user(tmp, (unsigned long *) data);
+ pr_debug("PEEKUSR: rdword=0x%08lx\n", tmp);
+ break;
+ /* write the word at location addr in the USER area */
+ case PTRACE_POKEUSR:
+ pr_debug("POKEUSR: addr=0x%08lx, data=0x%08lx\n", addr, data);
+ ret = -EIO;
+ if (addr & 3)
+ break;
+
+ addr = addr >> 2; /* temporary hack. */
+
+ if (addr == PTR_ESTATUS) {
+ data &= SR_MASK;
+ data |= get_reg(child, PTR_ESTATUS) & ~(SR_MASK);
+ }
+ if (addr < ARRAY_SIZE(regoff)) {
+ if (put_reg(child, addr, data))
+ break;
+ ret = 0;
+ break;
+ }
+ break;
+ /* Get all gp regs from the child. */
+ case PTRACE_GETREGS:
+ pr_debug("GETREGS\n");
+ for (i = 0; i < ARRAY_SIZE(regoff); i++) {
+ tmp = get_reg(child, i);
+ if (put_user(tmp, (unsigned long *) data)) {
+ ret = -EFAULT;
+ break;
+ }
+ data += sizeof(long);
+ }
+ ret = 0;
+ break;
+ /* Set all gp regs in the child. */
+ case PTRACE_SETREGS:
+ pr_debug("SETREGS\n");
+ for (i = 0; i < ARRAY_SIZE(regoff); i++) {
+ if (get_user(tmp, (unsigned long *) data)) {
+ ret = -EFAULT;
+ break;
+ }
+ if (i == PTR_ESTATUS) {
+ tmp &= SR_MASK;
+ tmp |= get_reg(child, PTR_ESTATUS) & ~(SR_MASK);
+ }
+ put_reg(child, i, tmp);
+ data += sizeof(long);
+ }
+ ret = 0;
+ break;
+ default:
+ ret = ptrace_request(child, request, addr, data);
+ }
+
+ return ret;
+}
+
+asmlinkage void syscall_trace(void)
+{
+ if (!test_thread_flag(TIF_SYSCALL_TRACE))
+ return;
+ if (!(current->ptrace & PT_PTRACED))
+ return;
+ current->exit_code = SIGTRAP;
+ current->state = TASK_STOPPED;
+ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+ ? 0x80 : 0));
+ /*
+ * this isn't the same as continuing with a signal, but it will do
+ * for normal use. strace only continues with a signal if the
+ * stopping signal is not SIGTRAP. -brl
+ */
+ if (current->exit_code) {
+ send_sig(current->exit_code, current, 1);
+ current->exit_code = 0;
+ }
+}
--
1.8.3.2
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists