-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ptrace support for nios2. Signed-off-by: Ley Foon Tan <lftan@altera.com>
- Loading branch information
Ley Foon Tan
committed
Dec 8, 2014
1 parent
42381bf
commit 106174d
Showing
3 changed files
with
319 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |