Commit | Line | Data |
---|---|---|
e9d0704a GH |
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 | } |