Commit b8fc4428 authored by Daniel Jacobowitz's avatar Daniel Jacobowitz

Hand-merge with Ingo's changes

parents 3fa327f8 a866697c
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
/* 0x4200-0x4300 are reserved for architecture-independent additions. */ /* 0x4200-0x4300 are reserved for architecture-independent additions. */
#define PTRACE_SETOPTIONS 0x4200 #define PTRACE_SETOPTIONS 0x4200
#define PTRACE_GETEVENTMSG 0x4201 #define PTRACE_GETEVENTMSG 0x4201
#define PTRACE_GETSIGINFO 0x4202
#define PTRACE_SETSIGINFO 0x4203
/* options set using PTRACE_SETOPTIONS */ /* options set using PTRACE_SETOPTIONS */
#define PTRACE_O_TRACESYSGOOD 0x00000001 #define PTRACE_O_TRACESYSGOOD 0x00000001
...@@ -33,12 +35,16 @@ ...@@ -33,12 +35,16 @@
#define PTRACE_O_TRACEVFORK 0x00000004 #define PTRACE_O_TRACEVFORK 0x00000004
#define PTRACE_O_TRACECLONE 0x00000008 #define PTRACE_O_TRACECLONE 0x00000008
#define PTRACE_O_TRACEEXEC 0x00000010 #define PTRACE_O_TRACEEXEC 0x00000010
#define PTRACE_O_TRACEVFORKDONE 0x00000020
#define PTRACE_O_TRACEEXIT 0x00000040
/* Wait extended result codes for the above trace options. */ /* Wait extended result codes for the above trace options. */
#define PTRACE_EVENT_FORK 1 #define PTRACE_EVENT_FORK 1
#define PTRACE_EVENT_VFORK 2 #define PTRACE_EVENT_VFORK 2
#define PTRACE_EVENT_CLONE 3 #define PTRACE_EVENT_CLONE 3
#define PTRACE_EVENT_EXEC 4 #define PTRACE_EVENT_EXEC 4
#define PTRACE_EVENT_VFORK_DONE 5
#define PTRACE_EVENT_EXIT 6
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <linux/sched.h> #include <linux/sched.h>
......
...@@ -405,6 +405,7 @@ struct task_struct { ...@@ -405,6 +405,7 @@ struct task_struct {
struct backing_dev_info *backing_dev_info; struct backing_dev_info *backing_dev_info;
unsigned long ptrace_message; unsigned long ptrace_message;
siginfo_t *last_siginfo; /* For ptrace use. */
}; };
extern void __put_task_struct(struct task_struct *tsk); extern void __put_task_struct(struct task_struct *tsk);
...@@ -445,6 +446,8 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0) ...@@ -445,6 +446,8 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0)
#define PT_TRACE_VFORK 0x00000020 #define PT_TRACE_VFORK 0x00000020
#define PT_TRACE_CLONE 0x00000040 #define PT_TRACE_CLONE 0x00000040
#define PT_TRACE_EXEC 0x00000080 #define PT_TRACE_EXEC 0x00000080
#define PT_TRACE_VFORK_DONE 0x00000100
#define PT_TRACE_EXIT 0x00000200
#if CONFIG_SMP #if CONFIG_SMP
extern void set_cpus_allowed(task_t *p, unsigned long new_mask); extern void set_cpus_allowed(task_t *p, unsigned long new_mask);
......
...@@ -198,6 +198,17 @@ static inline int has_stopped_jobs(int pgrp) ...@@ -198,6 +198,17 @@ static inline int has_stopped_jobs(int pgrp)
for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid) { for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid) {
if (p->state != TASK_STOPPED) if (p->state != TASK_STOPPED)
continue; continue;
/* If p is stopped by a debugger on a signal that won't
stop it, then don't count p as stopped. This isn't
perfect but it's a good approximation. */
if (unlikely (p->ptrace)
&& p->exit_code != SIGSTOP
&& p->exit_code != SIGTSTP
&& p->exit_code != SIGTTOU
&& p->exit_code != SIGTTIN)
continue;
retval = 1; retval = 1;
break; break;
} }
...@@ -570,7 +581,7 @@ static void exit_notify(void) ...@@ -570,7 +581,7 @@ static void exit_notify(void)
* is about to become orphaned. * is about to become orphaned.
*/ */
t = current->parent; t = current->real_parent;
if ((t->pgrp != current->pgrp) && if ((t->pgrp != current->pgrp) &&
(t->session == current->session) && (t->session == current->session) &&
...@@ -603,8 +614,16 @@ static void exit_notify(void) ...@@ -603,8 +614,16 @@ static void exit_notify(void)
current->exit_signal = SIGCHLD; current->exit_signal = SIGCHLD;
if (current->exit_signal != -1) /* If something other than our normal parent is ptracing us, then
* send it a SIGCHLD instead of honoring exit_signal. exit_signal
* only has special meaning to our real parent.
*/
if (current->exit_signal != -1) {
if (current->parent == current->real_parent)
do_notify_parent(current, current->exit_signal); do_notify_parent(current, current->exit_signal);
else
do_notify_parent(current, SIGCHLD);
}
current->state = TASK_ZOMBIE; current->state = TASK_ZOMBIE;
/* /*
...@@ -637,6 +656,9 @@ NORET_TYPE void do_exit(long code) ...@@ -637,6 +656,9 @@ NORET_TYPE void do_exit(long code)
profile_exit_task(tsk); profile_exit_task(tsk);
if (unlikely(current->ptrace & PT_TRACE_EXIT))
ptrace_notify((PTRACE_EVENT_EXIT << 8) | SIGTRAP);
fake_volatile: fake_volatile:
acct_process(code); acct_process(code);
__exit_mm(tsk); __exit_mm(tsk);
......
...@@ -1065,9 +1065,11 @@ struct task_struct *do_fork(unsigned long clone_flags, ...@@ -1065,9 +1065,11 @@ struct task_struct *do_fork(unsigned long clone_flags,
ptrace_notify ((trace << 8) | SIGTRAP); ptrace_notify ((trace << 8) | SIGTRAP);
} }
if (clone_flags & CLONE_VFORK) if (clone_flags & CLONE_VFORK) {
wait_for_completion(&vfork); wait_for_completion(&vfork);
else if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE))
ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP);
} else
/* /*
* Let the child process run first, to avoid most of the * Let the child process run first, to avoid most of the
* COW overhead when the child exec()s afterwards. * COW overhead when the child exec()s afterwards.
......
...@@ -277,15 +277,43 @@ static int ptrace_setoptions(struct task_struct *child, long data) ...@@ -277,15 +277,43 @@ static int ptrace_setoptions(struct task_struct *child, long data)
else else
child->ptrace &= ~PT_TRACE_EXEC; child->ptrace &= ~PT_TRACE_EXEC;
if (data & PTRACE_O_TRACEVFORKDONE)
child->ptrace |= PT_TRACE_VFORK_DONE;
else
child->ptrace &= ~PT_TRACE_VFORK_DONE;
if (data & PTRACE_O_TRACEEXIT)
child->ptrace |= PT_TRACE_EXIT;
else
child->ptrace &= ~PT_TRACE_EXIT;
if ((data & (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK if ((data & (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK
| PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE
| PTRACE_O_TRACEEXEC)) | PTRACE_O_TRACEEXEC | PTRACE_O_TRACEEXIT
| PTRACE_O_TRACEVFORKDONE))
!= data) != data)
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
static int ptrace_getsiginfo(struct task_struct *child, long data)
{
if (child->last_siginfo == NULL)
return -EINVAL;
return copy_siginfo_to_user ((siginfo_t *) data, child->last_siginfo);
}
static int ptrace_setsiginfo(struct task_struct *child, long data)
{
if (child->last_siginfo == NULL)
return -EINVAL;
if (copy_from_user (child->last_siginfo, (siginfo_t *) data,
sizeof (siginfo_t)) != 0)
return -EFAULT;
return 0;
}
int ptrace_request(struct task_struct *child, long request, int ptrace_request(struct task_struct *child, long request,
long addr, long data) long addr, long data)
{ {
...@@ -301,6 +329,12 @@ int ptrace_request(struct task_struct *child, long request, ...@@ -301,6 +329,12 @@ int ptrace_request(struct task_struct *child, long request,
case PTRACE_GETEVENTMSG: case PTRACE_GETEVENTMSG:
ret = put_user(child->ptrace_message, (unsigned long *) data); ret = put_user(child->ptrace_message, (unsigned long *) data);
break; break;
case PTRACE_GETSIGINFO:
ret = ptrace_getsiginfo(child, data);
break;
case PTRACE_SETSIGINFO:
ret = ptrace_setsiginfo(child, data);
break;
default: default:
break; break;
} }
......
...@@ -1404,17 +1404,23 @@ int get_signal_to_deliver(siginfo_t *info, struct pt_regs *regs) ...@@ -1404,17 +1404,23 @@ int get_signal_to_deliver(siginfo_t *info, struct pt_regs *regs)
/* Let the debugger run. */ /* Let the debugger run. */
current->exit_code = signr; current->exit_code = signr;
current->last_siginfo = info;
set_current_state(TASK_STOPPED); set_current_state(TASK_STOPPED);
notify_parent(current, SIGCHLD); notify_parent(current, SIGCHLD);
schedule(); schedule();
current->last_siginfo = NULL;
/* We're back. Did the debugger cancel the sig? */ /* We're back. Did the debugger cancel the sig? */
signr = current->exit_code; signr = current->exit_code;
if (signr == 0) if (signr == 0)
continue; continue;
current->exit_code = 0; current->exit_code = 0;
/* Update the siginfo structure. Is this good? */ /* Update the siginfo structure if the signal has
changed. If the debugger wanted something
specific in the siginfo structure then it should
have updated *info via PTRACE_SETSIGINFO. */
if (signr != info->si_signo) { if (signr != info->si_signo) {
info->si_signo = signr; info->si_signo = signr;
info->si_errno = 0; info->si_errno = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment