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
,
120 memset(&info
, 0, sizeof(info
));
121 info
.si_signo
= SIGTRAP
;
122 info
.si_code
= TRAP_BRKPT
;
125 info
.si_addr
= UPT_IS_USER(regs
) ? (void __user
*) UPT_IP(regs
) : NULL
;
127 /* Send us the fake SIGTRAP */
128 force_sig_info(SIGTRAP
, &info
, tsk
);
132 * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
133 * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
135 int syscall_trace_enter(struct pt_regs
*regs
)
137 audit_syscall_entry(UPT_SYSCALL_NR(®s
->regs
),
138 UPT_SYSCALL_ARG1(®s
->regs
),
139 UPT_SYSCALL_ARG2(®s
->regs
),
140 UPT_SYSCALL_ARG3(®s
->regs
),
141 UPT_SYSCALL_ARG4(®s
->regs
));
143 if (!test_thread_flag(TIF_SYSCALL_TRACE
))
146 return tracehook_report_syscall_entry(regs
);
149 void syscall_trace_leave(struct pt_regs
*regs
)
151 int ptraced
= current
->ptrace
;
153 audit_syscall_exit(regs
);
155 /* Fake a debug trap */
156 if (ptraced
& PT_DTRACE
)
157 send_sigtrap(current
, ®s
->regs
, 0);
159 if (!test_thread_flag(TIF_SYSCALL_TRACE
))
162 tracehook_report_syscall_exit(regs
, 0);
163 /* force do_signal() --> is_syscall() */
164 if (ptraced
& PT_PTRACED
)
165 set_thread_flag(TIF_SIGPENDING
);