Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/um/kernel/ptrace.c
26444 views
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
#define CREATE_TRACE_POINTS
13
#include <trace/events/syscalls.h>
14
15
void user_enable_single_step(struct task_struct *child)
16
{
17
set_tsk_thread_flag(child, TIF_SINGLESTEP);
18
19
#ifdef SUBARCH_SET_SINGLESTEPPING
20
SUBARCH_SET_SINGLESTEPPING(child, 1);
21
#endif
22
}
23
24
void user_disable_single_step(struct task_struct *child)
25
{
26
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
27
28
#ifdef SUBARCH_SET_SINGLESTEPPING
29
SUBARCH_SET_SINGLESTEPPING(child, 0);
30
#endif
31
}
32
33
/*
34
* Called by kernel/ptrace.c when detaching..
35
*/
36
void ptrace_disable(struct task_struct *child)
37
{
38
user_disable_single_step(child);
39
}
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_TRACEPOINT))
133
trace_sys_enter(regs, UPT_SYSCALL_NR(&regs->regs));
134
135
if (!test_thread_flag(TIF_SYSCALL_TRACE))
136
return 0;
137
138
return ptrace_report_syscall_entry(regs);
139
}
140
141
void syscall_trace_leave(struct pt_regs *regs)
142
{
143
int ptraced = current->ptrace;
144
145
audit_syscall_exit(regs);
146
147
/* Fake a debug trap */
148
if (test_thread_flag(TIF_SINGLESTEP))
149
send_sigtrap(&regs->regs, 0);
150
151
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
152
trace_sys_exit(regs, PT_REGS_SYSCALL_RET(regs));
153
154
if (!test_thread_flag(TIF_SYSCALL_TRACE))
155
return;
156
157
ptrace_report_syscall_exit(regs, 0);
158
/* force do_signal() --> is_syscall() */
159
if (ptraced & PT_PTRACED)
160
set_thread_flag(TIF_SIGPENDING);
161
}
162
163