nios2: ptrace support
Add ptrace support for nios2. Signed-off-by: Ley Foon Tan <lftan@altera.com>
This commit is contained in:
parent
42381bf1f2
commit
106174d0d8
33
arch/nios2/include/asm/ptrace.h
Normal file
33
arch/nios2/include/asm/ptrace.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Altera Corporation
|
||||
* Copyright (C) 2010 Tobias Klauser <tklauser@distanz.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__
|
||||
#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)
|
||||
|
||||
int do_syscall_trace_enter(void);
|
||||
void do_syscall_trace_exit(void);
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* _ASM_NIOS2_PTRACE_H */
|
120
arch/nios2/include/uapi/asm/ptrace.h
Normal file
120
arch/nios2/include/uapi/asm/ptrace.h
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Tobias Klauser <tklauser@distanz.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
|
||||
|
||||
#define NUM_PTRACE_REG (PTR_TLBMISC + 1)
|
||||
|
||||
/* 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 */
|
166
arch/nios2/kernel/ptrace.c
Normal file
166
arch/nios2/kernel/ptrace.c
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Altera Corporation
|
||||
* Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
|
||||
*
|
||||
* 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/elf.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/regset.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/tracehook.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/user.h>
|
||||
|
||||
static int genregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
const struct pt_regs *regs = task_pt_regs(target);
|
||||
const struct switch_stack *sw = (struct switch_stack *)regs - 1;
|
||||
int ret = 0;
|
||||
|
||||
#define REG_O_ZERO_RANGE(START, END) \
|
||||
if (!ret) \
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \
|
||||
START * 4, (END * 4) + 4);
|
||||
|
||||
#define REG_O_ONE(PTR, LOC) \
|
||||
if (!ret) \
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
|
||||
LOC * 4, (LOC * 4) + 4);
|
||||
|
||||
#define REG_O_RANGE(PTR, START, END) \
|
||||
if (!ret) \
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
|
||||
START * 4, (END * 4) + 4);
|
||||
|
||||
REG_O_ZERO_RANGE(PTR_R0, PTR_R0);
|
||||
REG_O_RANGE(®s->r1, PTR_R1, PTR_R7);
|
||||
REG_O_RANGE(®s->r8, PTR_R8, PTR_R15);
|
||||
REG_O_RANGE(sw, PTR_R16, PTR_R23);
|
||||
REG_O_ZERO_RANGE(PTR_R24, PTR_R25); /* et and bt */
|
||||
REG_O_ONE(®s->gp, PTR_GP);
|
||||
REG_O_ONE(®s->sp, PTR_SP);
|
||||
REG_O_ONE(®s->fp, PTR_FP);
|
||||
REG_O_ONE(®s->ea, PTR_EA);
|
||||
REG_O_ZERO_RANGE(PTR_BA, PTR_BA);
|
||||
REG_O_ONE(®s->ra, PTR_RA);
|
||||
REG_O_ONE(®s->ea, PTR_PC); /* use ea for PC */
|
||||
if (!ret)
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
PTR_STATUS * 4, -1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the thread state from a regset passed in via ptrace
|
||||
*/
|
||||
static int genregs_set(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
const struct switch_stack *sw = (struct switch_stack *)regs - 1;
|
||||
int ret = 0;
|
||||
|
||||
#define REG_IGNORE_RANGE(START, END) \
|
||||
if (!ret) \
|
||||
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, \
|
||||
START * 4, (END * 4) + 4);
|
||||
|
||||
#define REG_IN_ONE(PTR, LOC) \
|
||||
if (!ret) \
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \
|
||||
(void *)(PTR), LOC * 4, (LOC * 4) + 4);
|
||||
|
||||
#define REG_IN_RANGE(PTR, START, END) \
|
||||
if (!ret) \
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \
|
||||
(void *)(PTR), START * 4, (END * 4) + 4);
|
||||
|
||||
REG_IGNORE_RANGE(PTR_R0, PTR_R0);
|
||||
REG_IN_RANGE(®s->r1, PTR_R1, PTR_R7);
|
||||
REG_IN_RANGE(®s->r8, PTR_R8, PTR_R15);
|
||||
REG_IN_RANGE(sw, PTR_R16, PTR_R23);
|
||||
REG_IGNORE_RANGE(PTR_R24, PTR_R25); /* et and bt */
|
||||
REG_IN_ONE(®s->gp, PTR_GP);
|
||||
REG_IN_ONE(®s->sp, PTR_SP);
|
||||
REG_IN_ONE(®s->fp, PTR_FP);
|
||||
REG_IN_ONE(®s->ea, PTR_EA);
|
||||
REG_IGNORE_RANGE(PTR_BA, PTR_BA);
|
||||
REG_IN_ONE(®s->ra, PTR_RA);
|
||||
REG_IN_ONE(®s->ea, PTR_PC); /* use ea for PC */
|
||||
if (!ret)
|
||||
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
||||
PTR_STATUS * 4, -1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Define the register sets available on Nios2 under Linux
|
||||
*/
|
||||
enum nios2_regset {
|
||||
REGSET_GENERAL,
|
||||
};
|
||||
|
||||
static const struct user_regset nios2_regsets[] = {
|
||||
[REGSET_GENERAL] = {
|
||||
.core_note_type = NT_PRSTATUS,
|
||||
.n = NUM_PTRACE_REG,
|
||||
.size = sizeof(unsigned long),
|
||||
.align = sizeof(unsigned long),
|
||||
.get = genregs_get,
|
||||
.set = genregs_set,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct user_regset_view nios2_user_view = {
|
||||
.name = "nios2",
|
||||
.e_machine = ELF_ARCH,
|
||||
.ei_osabi = ELF_OSABI,
|
||||
.regsets = nios2_regsets,
|
||||
.n = ARRAY_SIZE(nios2_regsets)
|
||||
};
|
||||
|
||||
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
|
||||
{
|
||||
return &nios2_user_view;
|
||||
}
|
||||
|
||||
void ptrace_disable(struct task_struct *child)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
long arch_ptrace(struct task_struct *child, long request, unsigned long addr,
|
||||
unsigned long data)
|
||||
{
|
||||
return ptrace_request(child, request, addr, data);
|
||||
}
|
||||
|
||||
asmlinkage int do_syscall_trace_enter(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (test_thread_flag(TIF_SYSCALL_TRACE))
|
||||
ret = tracehook_report_syscall_entry(task_pt_regs(current));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
asmlinkage void do_syscall_trace_exit(void)
|
||||
{
|
||||
if (test_thread_flag(TIF_SYSCALL_TRACE))
|
||||
tracehook_report_syscall_exit(task_pt_regs(current), 0);
|
||||
}
|
Loading…
Reference in New Issue
Block a user