diff options
author | Greentime Hu <greentime@andestech.com> | 2017-10-25 02:32:12 -0400 |
---|---|---|
committer | Greentime Hu <greentime@andestech.com> | 2018-02-21 21:44:34 -0500 |
commit | e9d0704aa134de05b21085e6e9dab863e7ab38f7 (patch) | |
tree | 9097860150f2f4c12024a108b5dc7d8ef83e64ac /arch/nds32 | |
parent | ace02e2badd12e34d781780517614c42dbbf8068 (diff) |
nds32: Debugging support
This patch adds ptrace support.
Signed-off-by: Vincent Chen <vincentc@andestech.com>
Signed-off-by: Greentime Hu <greentime@andestech.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/nds32')
-rw-r--r-- | arch/nds32/include/uapi/asm/ptrace.h | 25 | ||||
-rw-r--r-- | arch/nds32/kernel/ptrace.c | 119 |
2 files changed, 144 insertions, 0 deletions
diff --git a/arch/nds32/include/uapi/asm/ptrace.h b/arch/nds32/include/uapi/asm/ptrace.h new file mode 100644 index 000000000000..358c99e399d0 --- /dev/null +++ b/arch/nds32/include/uapi/asm/ptrace.h | |||
@@ -0,0 +1,25 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | // Copyright (C) 2005-2017 Andes Technology Corporation | ||
3 | |||
4 | #ifndef __UAPI_ASM_NDS32_PTRACE_H | ||
5 | #define __UAPI_ASM_NDS32_PTRACE_H | ||
6 | |||
7 | #ifndef __ASSEMBLY__ | ||
8 | |||
9 | /* | ||
10 | * User structures for general purpose register. | ||
11 | */ | ||
12 | struct user_pt_regs { | ||
13 | long uregs[26]; | ||
14 | long fp; | ||
15 | long gp; | ||
16 | long lp; | ||
17 | long sp; | ||
18 | long ipc; | ||
19 | long lb; | ||
20 | long le; | ||
21 | long lc; | ||
22 | long syscallno; | ||
23 | }; | ||
24 | #endif | ||
25 | #endif | ||
diff --git a/arch/nds32/kernel/ptrace.c b/arch/nds32/kernel/ptrace.c new file mode 100644 index 000000000000..eaaf7a999b20 --- /dev/null +++ b/arch/nds32/kernel/ptrace.c | |||
@@ -0,0 +1,119 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | // Copyright (C) 2005-2017 Andes Technology Corporation | ||
3 | |||
4 | #include <linux/ptrace.h> | ||
5 | #include <linux/regset.h> | ||
6 | #include <linux/tracehook.h> | ||
7 | #include <linux/elf.h> | ||
8 | #include <linux/sched/task_stack.h> | ||
9 | |||
10 | enum nds32_regset { | ||
11 | REGSET_GPR, | ||
12 | }; | ||
13 | |||
14 | static int gpr_get(struct task_struct *target, | ||
15 | const struct user_regset *regset, | ||
16 | unsigned int pos, unsigned int count, | ||
17 | void *kbuf, void __user * ubuf) | ||
18 | { | ||
19 | struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs; | ||
20 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1); | ||
21 | } | ||
22 | |||
23 | static int gpr_set(struct task_struct *target, const struct user_regset *regset, | ||
24 | unsigned int pos, unsigned int count, | ||
25 | const void *kbuf, const void __user * ubuf) | ||
26 | { | ||
27 | int err; | ||
28 | struct user_pt_regs newregs = task_pt_regs(target)->user_regs; | ||
29 | |||
30 | err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1); | ||
31 | if (err) | ||
32 | return err; | ||
33 | |||
34 | task_pt_regs(target)->user_regs = newregs; | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | static const struct user_regset nds32_regsets[] = { | ||
39 | [REGSET_GPR] = { | ||
40 | .core_note_type = NT_PRSTATUS, | ||
41 | .n = sizeof(struct user_pt_regs) / sizeof(u32), | ||
42 | .size = sizeof(elf_greg_t), | ||
43 | .align = sizeof(elf_greg_t), | ||
44 | .get = gpr_get, | ||
45 | .set = gpr_set} | ||
46 | }; | ||
47 | |||
48 | static const struct user_regset_view nds32_user_view = { | ||
49 | .name = "nds32", | ||
50 | .e_machine = EM_NDS32, | ||
51 | .regsets = nds32_regsets, | ||
52 | .n = ARRAY_SIZE(nds32_regsets) | ||
53 | }; | ||
54 | |||
55 | const struct user_regset_view *task_user_regset_view(struct task_struct *task) | ||
56 | { | ||
57 | return &nds32_user_view; | ||
58 | } | ||
59 | |||
60 | void ptrace_disable(struct task_struct *child) | ||
61 | { | ||
62 | user_disable_single_step(child); | ||
63 | } | ||
64 | |||
65 | /* do_ptrace() | ||
66 | * | ||
67 | * Provide ptrace defined service. | ||
68 | */ | ||
69 | long arch_ptrace(struct task_struct *child, long request, unsigned long addr, | ||
70 | unsigned long data) | ||
71 | { | ||
72 | int ret = -EIO; | ||
73 | |||
74 | switch (request) { | ||
75 | default: | ||
76 | ret = ptrace_request(child, request, addr, data); | ||
77 | break; | ||
78 | } | ||
79 | |||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | void user_enable_single_step(struct task_struct *child) | ||
84 | { | ||
85 | struct pt_regs *regs; | ||
86 | regs = task_pt_regs(child); | ||
87 | regs->ipsw |= PSW_mskHSS; | ||
88 | set_tsk_thread_flag(child, TIF_SINGLESTEP); | ||
89 | } | ||
90 | |||
91 | void user_disable_single_step(struct task_struct *child) | ||
92 | { | ||
93 | struct pt_regs *regs; | ||
94 | regs = task_pt_regs(child); | ||
95 | regs->ipsw &= ~PSW_mskHSS; | ||
96 | clear_tsk_thread_flag(child, TIF_SINGLESTEP); | ||
97 | } | ||
98 | |||
99 | /* sys_trace() | ||
100 | * | ||
101 | * syscall trace handler. | ||
102 | */ | ||
103 | |||
104 | asmlinkage int syscall_trace_enter(struct pt_regs *regs) | ||
105 | { | ||
106 | if (test_thread_flag(TIF_SYSCALL_TRACE)) { | ||
107 | if (tracehook_report_syscall_entry(regs)) | ||
108 | forget_syscall(regs); | ||
109 | } | ||
110 | return regs->syscallno; | ||
111 | } | ||
112 | |||
113 | asmlinkage void syscall_trace_leave(struct pt_regs *regs) | ||
114 | { | ||
115 | int step = test_thread_flag(TIF_SINGLESTEP); | ||
116 | if (step || test_thread_flag(TIF_SYSCALL_TRACE)) | ||
117 | tracehook_report_syscall_exit(regs, step); | ||
118 | |||
119 | } | ||