]>
git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - arch/um/kernel/ptrace.c
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
6 #include "linux/sched.h"
8 #include "linux/errno.h"
9 #include "linux/smp_lock.h"
10 #include "linux/security.h"
11 #include "linux/ptrace.h"
12 #include "linux/audit.h"
14 #include "linux/proc_mm.h"
16 #include "asm/ptrace.h"
17 #include "asm/uaccess.h"
18 #include "kern_util.h"
19 #include "skas_ptrace.h"
20 #include "sysdep/ptrace.h"
23 * Called by kernel/ptrace.c when detaching..
25 void ptrace_disable(struct task_struct
*child
)
27 child
->ptrace
&= ~PT_DTRACE
;
28 child
->thread
.singlestep_syscall
= 0;
31 long sys_ptrace(long request
, long pid
, long addr
, long data
)
33 struct task_struct
*child
;
38 if (request
== PTRACE_TRACEME
) {
39 /* are we already being traced? */
40 if (current
->ptrace
& PT_PTRACED
)
43 ret
= security_ptrace(current
->parent
, current
);
47 /* set the ptrace bit in the process flags. */
48 current
->ptrace
|= PT_PTRACED
;
53 read_lock(&tasklist_lock
);
54 child
= find_task_by_pid(pid
);
56 get_task_struct(child
);
57 read_unlock(&tasklist_lock
);
62 if (pid
== 1) /* you may not mess with init */
65 if (request
== PTRACE_ATTACH
) {
66 ret
= ptrace_attach(child
);
70 ret
= ptrace_check_attach(child
, request
== PTRACE_KILL
);
75 /* when I and D space are separate, these will need to be fixed. */
76 case PTRACE_PEEKTEXT
: /* read word at location addr. */
77 case PTRACE_PEEKDATA
: {
82 copied
= access_process_vm(child
, addr
, &tmp
, sizeof(tmp
), 0);
83 if (copied
!= sizeof(tmp
))
85 ret
= put_user(tmp
, (unsigned long __user
*) data
);
89 /* read the word at location addr in the USER area. */
90 case PTRACE_PEEKUSR
: {
94 if ((addr
& 3) || addr
< 0)
97 tmp
= 0; /* Default return condition */
98 if(addr
< MAX_REG_OFFSET
){
99 tmp
= getreg(child
, addr
);
101 else if((addr
>= offsetof(struct user
, u_debugreg
[0])) &&
102 (addr
<= offsetof(struct user
, u_debugreg
[7]))){
103 addr
-= offsetof(struct user
, u_debugreg
[0]);
105 tmp
= child
->thread
.arch
.debugregs
[addr
];
107 ret
= put_user(tmp
, (unsigned long __user
*) data
);
111 /* when I and D space are separate, this will have to be fixed. */
112 case PTRACE_POKETEXT
: /* write the word at location addr. */
113 case PTRACE_POKEDATA
:
115 if (access_process_vm(child
, addr
, &data
, sizeof(data
),
121 case PTRACE_POKEUSR
: /* write the word at location addr in the USER area */
123 if ((addr
& 3) || addr
< 0)
126 if (addr
< MAX_REG_OFFSET
) {
127 ret
= putreg(child
, addr
, data
);
130 #if 0 /* XXX x86_64 */
131 else if((addr
>= offsetof(struct user
, u_debugreg
[0])) &&
132 (addr
<= offsetof(struct user
, u_debugreg
[7]))){
133 addr
-= offsetof(struct user
, u_debugreg
[0]);
135 if((addr
== 4) || (addr
== 5)) break;
136 child
->thread
.arch
.debugregs
[addr
] = data
;
143 case PTRACE_SYSCALL
: /* continue and stop at next (return from) syscall */
144 case PTRACE_CONT
: { /* restart after signal. */
146 if (!valid_signal(data
))
149 child
->ptrace
&= ~PT_DTRACE
;
150 child
->thread
.singlestep_syscall
= 0;
151 if (request
== PTRACE_SYSCALL
) {
152 set_tsk_thread_flag(child
, TIF_SYSCALL_TRACE
);
155 clear_tsk_thread_flag(child
, TIF_SYSCALL_TRACE
);
157 child
->exit_code
= data
;
158 wake_up_process(child
);
164 * make the child exit. Best I can do is send it a sigkill.
165 * perhaps it should be put in the status that it wants to
170 if (child
->exit_state
== EXIT_ZOMBIE
) /* already dead */
173 child
->ptrace
&= ~PT_DTRACE
;
174 child
->thread
.singlestep_syscall
= 0;
175 child
->exit_code
= SIGKILL
;
176 wake_up_process(child
);
180 case PTRACE_SINGLESTEP
: { /* set the trap flag. */
182 if (!valid_signal(data
))
184 clear_tsk_thread_flag(child
, TIF_SYSCALL_TRACE
);
185 child
->ptrace
|= PT_DTRACE
;
186 child
->thread
.singlestep_syscall
= 0;
187 child
->exit_code
= data
;
188 /* give it a chance to run. */
189 wake_up_process(child
);
195 /* detach a process that was attached. */
196 ret
= ptrace_detach(child
, data
);
199 #ifdef PTRACE_GETREGS
200 case PTRACE_GETREGS
: { /* Get all gp regs from the child. */
201 if (!access_ok(VERIFY_WRITE
, (unsigned long *)data
,
206 for ( i
= 0; i
< MAX_REG_OFFSET
; i
+= sizeof(long) ) {
207 __put_user(getreg(child
, i
),
208 (unsigned long __user
*) data
);
209 data
+= sizeof(long);
215 #ifdef PTRACE_SETREGS
216 case PTRACE_SETREGS
: { /* Set all gp regs in the child. */
217 unsigned long tmp
= 0;
218 if (!access_ok(VERIFY_READ
, (unsigned *)data
,
223 for ( i
= 0; i
< MAX_REG_OFFSET
; i
+= sizeof(long) ) {
224 __get_user(tmp
, (unsigned long __user
*) data
);
225 putreg(child
, i
, tmp
);
226 data
+= sizeof(long);
232 #ifdef PTRACE_GETFPREGS
233 case PTRACE_GETFPREGS
: /* Get the child FPU state. */
234 ret
= get_fpregs(data
, child
);
237 #ifdef PTRACE_SETFPREGS
238 case PTRACE_SETFPREGS
: /* Set the child FPU state. */
239 ret
= set_fpregs(data
, child
);
242 #ifdef PTRACE_GETFPXREGS
243 case PTRACE_GETFPXREGS
: /* Get the child FPU state. */
244 ret
= get_fpxregs(data
, child
);
247 #ifdef PTRACE_SETFPXREGS
248 case PTRACE_SETFPXREGS
: /* Set the child FPU state. */
249 ret
= set_fpxregs(data
, child
);
252 case PTRACE_FAULTINFO
: {
253 struct ptrace_faultinfo fault
;
255 fault
= ((struct ptrace_faultinfo
)
256 { .is_write
= child
->thread
.err
,
257 .addr
= child
->thread
.cr2
});
258 ret
= copy_to_user((unsigned long __user
*) data
, &fault
,
264 case PTRACE_SIGPENDING
:
265 ret
= copy_to_user((unsigned long __user
*) data
,
266 &child
->pending
.signal
,
267 sizeof(child
->pending
.signal
));
271 struct ptrace_ldt ldt
;
273 if(copy_from_user(&ldt
, (unsigned long __user
*) data
,
279 /* This one is confusing, so just punt and return -EIO for
285 #ifdef CONFIG_PROC_MM
286 case PTRACE_SWITCH_MM
: {
287 struct mm_struct
*old
= child
->mm
;
288 struct mm_struct
*new = proc_mm_get_mm(data
);
295 atomic_inc(&new->mm_users
);
297 child
->active_mm
= new;
304 ret
= ptrace_request(child
, request
, addr
, data
);
308 put_task_struct(child
);
314 void send_sigtrap(struct task_struct
*tsk
, union uml_pt_regs
*regs
,
319 memset(&info
, 0, sizeof(info
));
320 info
.si_signo
= SIGTRAP
;
321 info
.si_code
= TRAP_BRKPT
;
324 info
.si_addr
= UPT_IS_USER(regs
) ? (void __user
*) UPT_IP(regs
) : NULL
;
326 /* Send us the fakey SIGTRAP */
327 force_sig_info(SIGTRAP
, &info
, tsk
);
330 /* XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
331 * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
333 void syscall_trace(union uml_pt_regs
*regs
, int entryexit
)
335 int is_singlestep
= (current
->ptrace
& PT_DTRACE
) && entryexit
;
338 if (unlikely(current
->audit_context
)) {
340 audit_syscall_entry(current
,
341 UPT_SYSCALL_NR(®s
->regs
),
342 UPT_SYSCALL_ARG1(®s
->regs
),
343 UPT_SYSCALL_ARG2(®s
->regs
),
344 UPT_SYSCALL_ARG3(®s
->regs
),
345 UPT_SYSCALL_ARG4(®s
->regs
));
347 audit_syscall_exit(current
,
348 UPT_SYSCALL_RET(®s
->regs
));
351 /* Fake a debug trap */
353 send_sigtrap(current
, regs
, 0);
355 if (!test_thread_flag(TIF_SYSCALL_TRACE
))
358 if (!(current
->ptrace
& PT_PTRACED
))
361 /* the 0x80 provides a way for the tracing parent to distinguish
362 between a syscall stop and SIGTRAP delivery */
363 tracesysgood
= (current
->ptrace
& PT_TRACESYSGOOD
);
364 ptrace_notify(SIGTRAP
| (tracesysgood
? 0x80 : 0));
366 if (entryexit
) /* force do_signal() --> is_syscall() */
367 set_thread_flag(TIF_SIGPENDING
);
369 /* this isn't the same as continuing with a signal, but it will do
370 * for normal use. strace only continues with a signal if the
371 * stopping signal is not SIGTRAP. -brl
373 if (current
->exit_code
) {
374 send_sig(current
->exit_code
, current
, 1);
375 current
->exit_code
= 0;
380 * Overrides for Emacs so that we follow Linus's tabbing style.
381 * Emacs will notice this stuff at the end of the file and automatically
382 * adjust the settings for this buffer only. This must remain at the end
384 * ---------------------------------------------------------------------------
386 * c-file-style: "linux"