]> Git Repo - J-linux.git/blob - arch/um/kernel/ptrace.c
Merge tag 'kbuild-v6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy...
[J-linux.git] / arch / um / kernel / ptrace.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4  */
5
6 #include <linux/audit.h>
7 #include <linux/ptrace.h>
8 #include <linux/sched.h>
9 #include <linux/uaccess.h>
10 #include <asm/ptrace-abi.h>
11
12 void user_enable_single_step(struct task_struct *child)
13 {
14         set_tsk_thread_flag(child, TIF_SINGLESTEP);
15
16 #ifdef SUBARCH_SET_SINGLESTEPPING
17         SUBARCH_SET_SINGLESTEPPING(child, 1);
18 #endif
19 }
20
21 void user_disable_single_step(struct task_struct *child)
22 {
23         clear_tsk_thread_flag(child, TIF_SINGLESTEP);
24
25 #ifdef SUBARCH_SET_SINGLESTEPPING
26         SUBARCH_SET_SINGLESTEPPING(child, 0);
27 #endif
28 }
29
30 /*
31  * Called by kernel/ptrace.c when detaching..
32  */
33 void ptrace_disable(struct task_struct *child)
34 {
35         user_disable_single_step(child);
36 }
37
38 extern int peek_user(struct task_struct * child, long addr, long data);
39 extern int poke_user(struct task_struct * child, long addr, long data);
40
41 long arch_ptrace(struct task_struct *child, long request,
42                  unsigned long addr, unsigned long data)
43 {
44         int i, ret;
45         unsigned long __user *p = (void __user *)data;
46         void __user *vp = p;
47
48         switch (request) {
49         /* read the word at location addr in the USER area. */
50         case PTRACE_PEEKUSR:
51                 ret = peek_user(child, addr, data);
52                 break;
53
54         /* write the word at location addr in the USER area */
55         case PTRACE_POKEUSR:
56                 ret = poke_user(child, addr, data);
57                 break;
58
59         case PTRACE_SYSEMU:
60         case PTRACE_SYSEMU_SINGLESTEP:
61                 ret = -EIO;
62                 break;
63
64 #ifdef PTRACE_GETREGS
65         case PTRACE_GETREGS: { /* Get all gp regs from the child. */
66                 if (!access_ok(p, MAX_REG_OFFSET)) {
67                         ret = -EIO;
68                         break;
69                 }
70                 for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
71                         __put_user(getreg(child, i), p);
72                         p++;
73                 }
74                 ret = 0;
75                 break;
76         }
77 #endif
78 #ifdef PTRACE_SETREGS
79         case PTRACE_SETREGS: { /* Set all gp regs in the child. */
80                 unsigned long tmp = 0;
81                 if (!access_ok(p, MAX_REG_OFFSET)) {
82                         ret = -EIO;
83                         break;
84                 }
85                 for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
86                         __get_user(tmp, p);
87                         putreg(child, i, tmp);
88                         p++;
89                 }
90                 ret = 0;
91                 break;
92         }
93 #endif
94         case PTRACE_GET_THREAD_AREA:
95                 ret = ptrace_get_thread_area(child, addr, vp);
96                 break;
97
98         case PTRACE_SET_THREAD_AREA:
99                 ret = ptrace_set_thread_area(child, addr, vp);
100                 break;
101
102         default:
103                 ret = ptrace_request(child, request, addr, data);
104                 if (ret == -EIO)
105                         ret = subarch_ptrace(child, request, addr, data);
106                 break;
107         }
108
109         return ret;
110 }
111
112 static void send_sigtrap(struct uml_pt_regs *regs, int error_code)
113 {
114         /* Send us the fake SIGTRAP */
115         force_sig_fault(SIGTRAP, TRAP_BRKPT,
116                         /* User-mode eip? */
117                         UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL);
118 }
119
120 /*
121  * XXX Check TIF_SINGLESTEP for singlestepping check and
122  * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
123  */
124 int syscall_trace_enter(struct pt_regs *regs)
125 {
126         audit_syscall_entry(UPT_SYSCALL_NR(&regs->regs),
127                             UPT_SYSCALL_ARG1(&regs->regs),
128                             UPT_SYSCALL_ARG2(&regs->regs),
129                             UPT_SYSCALL_ARG3(&regs->regs),
130                             UPT_SYSCALL_ARG4(&regs->regs));
131
132         if (!test_thread_flag(TIF_SYSCALL_TRACE))
133                 return 0;
134
135         return ptrace_report_syscall_entry(regs);
136 }
137
138 void syscall_trace_leave(struct pt_regs *regs)
139 {
140         int ptraced = current->ptrace;
141
142         audit_syscall_exit(regs);
143
144         /* Fake a debug trap */
145         if (test_thread_flag(TIF_SINGLESTEP))
146                 send_sigtrap(&regs->regs, 0);
147
148         if (!test_thread_flag(TIF_SYSCALL_TRACE))
149                 return;
150
151         ptrace_report_syscall_exit(regs, 0);
152         /* force do_signal() --> is_syscall() */
153         if (ptraced & PT_PTRACED)
154                 set_thread_flag(TIF_SIGPENDING);
155 }
This page took 0.034477 seconds and 4 git commands to generate.