2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3 * Licensed under the GPL
6 #include <linux/audit.h>
7 #include <linux/ptrace.h>
8 #include <linux/sched.h>
9 #include <linux/tracehook.h>
10 #include <linux/uaccess.h>
11 #include <asm/ptrace-abi.h>
13 void user_enable_single_step(struct task_struct
*child
)
15 child
->ptrace
|= PT_DTRACE
;
16 child
->thread
.singlestep_syscall
= 0;
18 #ifdef SUBARCH_SET_SINGLESTEPPING
19 SUBARCH_SET_SINGLESTEPPING(child
, 1);
23 void user_disable_single_step(struct task_struct
*child
)
25 child
->ptrace
&= ~PT_DTRACE
;
26 child
->thread
.singlestep_syscall
= 0;
28 #ifdef SUBARCH_SET_SINGLESTEPPING
29 SUBARCH_SET_SINGLESTEPPING(child
, 0);
34 * Called by kernel/ptrace.c when detaching..
36 void ptrace_disable(struct task_struct
*child
)
38 user_disable_single_step(child
);
41 extern int peek_user(struct task_struct
* child
, long addr
, long data
);
42 extern int poke_user(struct task_struct
* child
, long addr
, long data
);
44 long arch_ptrace(struct task_struct
*child
, long request
,
45 unsigned long addr
, unsigned long data
)
48 unsigned long __user
*p
= (void __user
*)data
;
52 /* read the word at location addr in the USER area. */
54 ret
= peek_user(child
, addr
, data
);
57 /* write the word at location addr in the USER area */
59 ret
= poke_user(child
, addr
, data
);
63 case PTRACE_SYSEMU_SINGLESTEP
:
68 case PTRACE_GETREGS
: { /* Get all gp regs from the child. */
69 if (!access_ok(VERIFY_WRITE
, p
, MAX_REG_OFFSET
)) {
73 for ( i
= 0; i
< MAX_REG_OFFSET
; i
+= sizeof(long) ) {
74 __put_user(getreg(child
, i
), p
);
82 case PTRACE_SETREGS
: { /* Set all gp regs in the child. */
83 unsigned long tmp
= 0;
84 if (!access_ok(VERIFY_READ
, p
, MAX_REG_OFFSET
)) {
88 for ( i
= 0; i
< MAX_REG_OFFSET
; i
+= sizeof(long) ) {
90 putreg(child
, i
, tmp
);
97 case PTRACE_GET_THREAD_AREA
:
98 ret
= ptrace_get_thread_area(child
, addr
, vp
);
101 case PTRACE_SET_THREAD_AREA
:
102 ret
= ptrace_set_thread_area(child
, addr
, vp
);
106 ret
= ptrace_request(child
, request
, addr
, data
);
108 ret
= subarch_ptrace(child
, request
, addr
, data
);
115 static void send_sigtrap(struct task_struct
*tsk
, struct uml_pt_regs
*regs
,
118 /* Send us the fake SIGTRAP */
119 force_sig_fault(SIGTRAP
, TRAP_BRKPT
,
121 UPT_IS_USER(regs
) ? (void __user
*) UPT_IP(regs
) : NULL
, tsk
);
125 * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
126 * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
128 int syscall_trace_enter(struct pt_regs
*regs
)
130 audit_syscall_entry(UPT_SYSCALL_NR(®s
->regs
),
131 UPT_SYSCALL_ARG1(®s
->regs
),
132 UPT_SYSCALL_ARG2(®s
->regs
),
133 UPT_SYSCALL_ARG3(®s
->regs
),
134 UPT_SYSCALL_ARG4(®s
->regs
));
136 if (!test_thread_flag(TIF_SYSCALL_TRACE
))
139 return tracehook_report_syscall_entry(regs
);
142 void syscall_trace_leave(struct pt_regs
*regs
)
144 int ptraced
= current
->ptrace
;
146 audit_syscall_exit(regs
);
148 /* Fake a debug trap */
149 if (ptraced
& PT_DTRACE
)
150 send_sigtrap(current
, ®s
->regs
, 0);
152 if (!test_thread_flag(TIF_SYSCALL_TRACE
))
155 tracehook_report_syscall_exit(regs
, 0);
156 /* force do_signal() --> is_syscall() */
157 if (ptraced
& PT_PTRACED
)
158 set_thread_flag(TIF_SIGPENDING
);