Skip to contentSkip to conversation

PATCH: ptrace support for fork/vfork/clone events [1/3]

PATCH Daniel Jacobowitz 1 participant 3 messages Oct 31, 2002

Subsystems (12)
Arm (32-bit) VFS MIPS MM core +8 more subsystems
lore
Share & tools
lore
#0 lore raw

I think I've answered everyone's concerns about these patches (again). Yet another Debian user asked me about their status last night, so I'm going to submit them again. I'm actively using the 2.4 backport, and I find it invaluable when debugging multi-process problems.

These three patches provide an event-mask interface for ptrace clients to watch for events in debugged processes. The supported events right now are fork, vfork, clone, and execve. This interface only triggers on the requested events, which makes it a great deal more practical than using PTRACE_SYSCALL.

Why is this necessary? Without it, there are some things GDB can't do. You can't step over a call to fork(), because when you do, the child process will hit the parent's step breakpoint and exit with SIGTRAP. You also can't choose to debug the child instead of the parent, because GDB doesn't have a chance to attach to it before it continues or exits.

There's no other viable way to do this without kernel support; using a trampoline is racy (as well as exceedingly complicated from a lightweight debugger standpoint).

The code is in three parts:
1. Factor out some common ptrace code; implement PTRACE_O_TRACESYSGOOD and PTRACE_SETOPTIONS for every architecture. This one will let me unify a great deal more of the architecture ptrace implementations later.
2. Add a new clone flag, CLONE_UNTRACED, and force it in all kernel_thread implementations. Needed by the next patch. This one touches every architecture and some of them in assembly; I've tried to get them all correct.
[Why is this needed? It's needed so that the debugger doesn't get triggered on, say, a kernel-started modprobe process or some other kernel thread. That'd confuse the debugger, beyond the other possible security/stability problems.]
3. Add PTRACE_GETEVENTMSG and four new flags to PTRACE_SETOPTIONS, to allow tracing fork, vfork, clone, and exec events.

The patches have been tested on i386, and a 2.4 backport tested on SH, MIPS, i386, PowerPC, and ARM; I have GDB using this mechanism and have run that through more stress tests than I really want to remember right now.

Future plans for the unified ptrace handling include READDATA/WRITEDATA for all architectures (someone else submitted code to do this just recently for 2.4, but mine's a little cleaner, I think) and page-protection based watchpoints for targets which don't have available hardware watchpoints (thanks to Klee at Apple for enlightening me on this concept :).

The three patches are available at:
http://crack.them.org/~drow/forks/

or from the BK tree at:
bk://nevyn.them.org:5000

Here's #1.

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas:
# ChangeSet 1.855 -> 1.856
# include/asm-i386/ptrace.h 1.2.1.1 -> 1.4
# arch/s390x/kernel/ptrace.c 1.7.1.1 -> 1.9
# include/linux/ptrace.h 1.3 -> 1.4
# arch/arm/kernel/ptrace.c 1.12.1.2 -> 1.14
# arch/sh/kernel/ptrace.c 1.7 -> 1.8
# arch/parisc/kernel/ptrace.c 1.4.1.1 -> 1.6
# include/asm-s390x/ptrace.h 1.3.1.1 -> 1.5
# arch/mips64/kernel/ptrace.c 1.6 -> 1.7
# arch/ppc/kernel/ptrace.c 1.10 -> 1.11
# arch/i386/kernel/ptrace.c 1.13.1.1 -> 1.15
# arch/x86_64/ia32/ptrace32.c 1.2.1.1 -> 1.4
# arch/ppc64/kernel/ptrace.c 1.3.1.1 -> 1.5
# arch/m68k/kernel/ptrace.c 1.7 -> 1.8
# include/asm-x86_64/ptrace.h 1.3.1.1 -> 1.5
# arch/x86_64/kernel/ptrace.c 1.3.1.1 -> 1.5
# arch/cris/kernel/ptrace.c 1.8 -> 1.9
# arch/ppc64/kernel/ptrace32.c 1.5.1.1 -> 1.7
# include/asm-arm/ptrace.h 1.2 -> 1.3

#	include/asm-mips/ptrace.h	1.2     -> 1.3    
#	arch/ia64/ia32/sys_ia32.c	1.24    -> 1.25   
#	include/asm-ia64/ptrace.h	1.4     -> 1.5    

# include/asm-s390/ptrace.h 1.5.1.1 -> 1.7
# include/asm-sh/ptrace.h 1.2 -> 1.3
# arch/alpha/kernel/ptrace.c 1.9 -> 1.10
# arch/s390/kernel/ptrace.c 1.8.1.1 -> 1.10
# include/asm-mips64/ptrace.h 1.1 -> 1.2
# arch/sparc64/kernel/ptrace.c 1.16 -> 1.17
# arch/ia64/kernel/ptrace.c 1.11.1.1 -> 1.13
# arch/sparc/kernel/ptrace.c 1.11 -> 1.12
# arch/mips/kernel/ptrace.c 1.8 -> 1.9
# kernel/ptrace.c 1.18 -> 1.19
#
# The following is the BitKeeper ChangeSet Log # --------------------------------------------
# 02/10/31 [email protected] 1.856
# Merge nevyn.them.org:/nevyn/big/kernel/linux-2.5

# into nevyn.them.org:/nevyn/big/kernel/test/linux-2.5-trace1
# --------------------------------------------
#
diff -Nru a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
--- a/arch/alpha/kernel/ptrace.c	Thu Oct 31 14:02:17 2002
+++ b/arch/alpha/kernel/ptrace.c	Thu Oct 31 14:02:17 2002
@@ -383,7 +383,7 @@
 		goto out;

default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
goto out;
}
out:
@@ -400,7 +400,8 @@
return;
if (!(current->ptrace & PT_PTRACED))
return;
- current->exit_code = SIGTRAP;
+ current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+ ? 0x80 : 0);
current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD);
schedule();

arch/arm/kernel/ptrace.c +1 -9
diff -Nru a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
@@ -692,16 +692,8 @@
 			ret = ptrace_setfpregs(child, (void *)data);
 			break;
 
-		case PTRACE_SETOPTIONS:
-			if (data & PTRACE_O_TRACESYSGOOD)
-				child->ptrace |= PT_TRACESYSGOOD;
-			else
-				child->ptrace &= ~PT_TRACESYSGOOD;
-			ret = 0;
-			break;
-
 		default:
-			ret = -EIO;
+			ret = ptrace_request(child, request, addr, data);
 			break;
 	}
 
arch/cris/kernel/ptrace.c +3 -5
diff -Nru a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c
@@ -292,7 +292,7 @@
 		}
 
 		default:
-			ret = -EIO;
+			ret = ptrace_request(child, request, addr, data);
 			break;
 	}
 out_tsk:
@@ -307,10 +307,8 @@
 	if ((current->ptrace & (PT_PTRACED | PT_TRACESYS)) !=
 	    (PT_PTRACED | PT_TRACESYS))
 		return;
-	/* TODO: make a way to distinguish between a syscall stop and SIGTRAP
-	 * delivery like in the i386 port ? 
-	 */
-	current->exit_code = SIGTRAP;
+	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+					? 0x80 : 0);
 	current->state = TASK_STOPPED;
 	notify_parent(current, SIGCHLD);
 	schedule();
arch/i386/kernel/ptrace.c +1 -10
diff -Nru a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
@@ -416,17 +416,8 @@
 		break;
 	}
 
-	case PTRACE_SETOPTIONS: {
-		if (data & PTRACE_O_TRACESYSGOOD)
-			child->ptrace |= PT_TRACESYSGOOD;
-		else
-			child->ptrace &= ~PT_TRACESYSGOOD;
-		ret = 0;
-		break;
-	}
-
 	default:
-		ret = -EIO;
+		ret = ptrace_request(child, request, addr, data);
 		break;
 	}
 out_tsk:
arch/ia64/ia32/sys_ia32.c +1 -1
diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
@@ -3076,7 +3076,7 @@
 		break;
 
 	      default:
-		ret = -EIO;
+		ret = ptrace_request(child, request, addr, data);
 		break;
 
 	}
arch/ia64/kernel/ptrace.c +1 -9
diff -Nru a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
@@ -1268,16 +1268,8 @@
 		ret = ptrace_setregs(child, (struct pt_all_user_regs*) data);
 		goto out_tsk;
 
-	      case PTRACE_SETOPTIONS:
-		if (data & PTRACE_O_TRACESYSGOOD)
-			child->ptrace |= PT_TRACESYSGOOD;
-		else
-			child->ptrace &= ~PT_TRACESYSGOOD;
-		ret = 0;
-		break;
-
 	      default:
-		ret = -EIO;
+		ret = ptrace_request(child, request, addr, data);
 		goto out_tsk;
 	}
   out_tsk:
arch/m68k/kernel/ptrace.c +3 -2
diff -Nru a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
@@ -355,7 +355,7 @@
 		}
 
 		default:
-			ret = -EIO;
+			ret = ptrace_request(child, request, addr, data);
 			break;
 	}
 out_tsk:
@@ -370,7 +370,8 @@
 	if (!current->thread.work.delayed_trace &&
 	    !current->thread.work.syscall_trace)
 		return;
-	current->exit_code = SIGTRAP;
+	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+					? 0x80 : 0);
 	current->state = TASK_STOPPED;
 	notify_parent(current, SIGCHLD);
 	schedule();
arch/mips/kernel/ptrace.c +1 -9
diff -Nru a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
@@ -304,16 +304,8 @@
 		res = ptrace_detach(child, data);
 		break;
 
-	case PTRACE_SETOPTIONS:
-		if (data & PTRACE_O_TRACESYSGOOD)
-			child->ptrace |= PT_TRACESYSGOOD;
-		else
-			child->ptrace &= ~PT_TRACESYSGOOD;
-		res = 0;
-		break;
-
 	default:
-		res = -EIO;
+		res = ptrace_request(child, request, addr, data);
 		goto out;
 	}
 out_tsk:
arch/mips64/kernel/ptrace.c +2 -20
diff -Nru a/arch/mips64/kernel/ptrace.c b/arch/mips64/kernel/ptrace.c
@@ -275,17 +275,8 @@
 		ret = ptrace_detach(child, data);
 		break;
 
-	case PTRACE_SETOPTIONS: {
-		if (data & PTRACE_O_TRACESYSGOOD)
-			child->ptrace |= PT_TRACESYSGOOD;
-		else
-			child->ptrace &= ~PT_TRACESYSGOOD;
-		ret = 0;
-		break;
-	}
-
 	default:
-		ret = -EIO;
+		ret = ptrace_request(child, request, addr, data);
 		break;
 	}
 
@@ -535,17 +526,8 @@
 		ret = ptrace_detach(child, data);
 		break;
 
-	case PTRACE_SETOPTIONS: {
-		if (data & PTRACE_O_TRACESYSGOOD)
-			child->ptrace |= PT_TRACESYSGOOD;
-		else
-			child->ptrace &= ~PT_TRACESYSGOOD;
-		ret = 0;
-		break;
-	}
-
 	default:
-		ret = -EIO;
+		ret = ptrace_request(child, request, addr, data);
 		break;
 	}
 
arch/parisc/kernel/ptrace.c +3 -2
diff -Nru a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
@@ -385,7 +385,7 @@
 		goto out_tsk;
 
 	default:
-		ret = -EIO;
+		ret = ptrace_request(child, request, addr, data);
 		goto out_tsk;
 	}
 
@@ -409,7 +409,8 @@
 		return;
 	if (!(current->ptrace & PT_PTRACED))
 		return;
-	current->exit_code = SIGTRAP;
+	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+					? 0x80 : 0);
 	current->state = TASK_STOPPED;
 	notify_parent(current, SIGCHLD);
 	schedule();
arch/ppc/kernel/ptrace.c +3 -2
diff -Nru a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
@@ -339,7 +339,7 @@
 #endif
 
 	default:
-		ret = -EIO;
+		ret = ptrace_request(child, request, addr, data);
 		break;
 	}
 out_tsk:
@@ -354,7 +354,8 @@
         if (!test_thread_flag(TIF_SYSCALL_TRACE)
 	    || !(current->ptrace & PT_PTRACED))
 		return;
-	current->exit_code = SIGTRAP;
+	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+					? 0x80 : 0);
 	current->state = TASK_STOPPED;
 	notify_parent(current, SIGCHLD);
 	schedule();
arch/ppc64/kernel/ptrace.c +3 -2
diff -Nru a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c
@@ -276,7 +276,7 @@
 	}
 
 	default:
-		ret = -EIO;
+		ret = ptrace_request(child, request, addr, data);
 		break;
 	}
 out_tsk:
@@ -292,7 +292,8 @@
 		return;
 	if (!(current->ptrace & PT_PTRACED))
 		return;
-	current->exit_code = SIGTRAP;
+	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+					? 0x80 : 0);
 	current->state = TASK_STOPPED;
 	notify_parent(current, SIGCHLD);
 	schedule();
arch/ppc64/kernel/ptrace32.c +1 -1
diff -Nru a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c
@@ -413,7 +413,7 @@
 
 
 	default:
-		ret = -EIO;
+		ret = ptrace_request(child, request, addr, data);
 		break;
 	}
 out_tsk:
arch/s390/kernel/ptrace.c +1 -8
diff -Nru a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
@@ -307,15 +307,8 @@
 			copied += sizeof(unsigned long);
 		}
 		return 0;
-
-	case PTRACE_SETOPTIONS:
-		if (data & PTRACE_O_TRACESYSGOOD)
-			child->ptrace |= PT_TRACESYSGOOD;
-		else
-			child->ptrace &= ~PT_TRACESYSGOOD;
-		return 0;
 	}
-	return -EIO;
+	return ptrace_request(child, request, addr, data);
 }
 
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
arch/s390x/kernel/ptrace.c +3 -9
diff -Nru a/arch/s390x/kernel/ptrace.c b/arch/s390x/kernel/ptrace.c
@@ -261,7 +261,7 @@
 		}
 		return 0;
 	}
-	return -EIO;
+	return ptrace_request(child, request, addr, data);
 }
 
 #ifdef CONFIG_S390_SUPPORT
@@ -469,7 +469,7 @@
 		}
 		return 0;
 	}
-	return -EIO;
+	return ptrace_request(child, request, addr, data);
 }
 #endif
 
@@ -538,12 +538,6 @@
 		/* detach a process that was attached. */
 		return ptrace_detach(child, data);
 
-	case PTRACE_SETOPTIONS:
-		if (data & PTRACE_O_TRACESYSGOOD)
-			child->ptrace |= PT_TRACESYSGOOD;
-		else
-			child->ptrace &= ~PT_TRACESYSGOOD;
-		return 0;
 	/* Do requests that differ for 31/64 bit */
 	default:
 #ifdef CONFIG_S390_SUPPORT
@@ -551,8 +545,8 @@
 			return do_ptrace_emu31(child, request, addr, data);
 #endif
 		return do_ptrace_normal(child, request, addr, data);
-		
 	}
+	/* Not reached.  */
 	return -EIO;
 }
 
arch/sh/kernel/ptrace.c +1 -10
diff -Nru a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c
@@ -356,17 +356,8 @@
 		ret = ptrace_detach(child, data);
 		break;
 
-	case PTRACE_SETOPTIONS: {
-		if (data & PTRACE_O_TRACESYSGOOD)
-			child->ptrace |= PT_TRACESYSGOOD;
-		else
-			child->ptrace &= ~PT_TRACESYSGOOD;
-		ret = 0;
-		break;
-	}
-
 	default:
-		ret = -EIO;
+		ret = ptrace_request(child, request, addr, data);
 		break;
 	}
 out_tsk:
arch/sparc/kernel/ptrace.c +9 -3
diff -Nru a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
@@ -584,10 +584,15 @@
 
 	/* PTRACE_DUMPCORE unsupported... */
 
-	default:
-		pt_error_return(regs, EIO);
+	default: {
+		int err = ptrace_request(child, request, addr, data);
+		if (err)
+			pt_error_return(regs, -err);
+		else
+			pt_succ_return(regs, 0);
 		goto out_tsk;
 	}
+	}
 out_tsk:
 	if (child)
 		put_task_struct(child);
@@ -604,7 +609,8 @@
 		return;
 	if (!(current->ptrace & PT_PTRACED))
 		return;
-	current->exit_code = SIGTRAP;
+	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+					? 0x80 : 0);
 	current->state = TASK_STOPPED;
 	current->thread.flags ^= MAGIC_CONSTANT;
 	notify_parent(current, SIGCHLD);
arch/sparc64/kernel/ptrace.c +9 -3
diff -Nru a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
@@ -571,10 +571,15 @@
 
 	/* PTRACE_DUMPCORE unsupported... */
 
-	default:
-		pt_error_return(regs, EIO);
+	default: {
+		int err = ptrace_request(child, request, addr, data);
+		if (err)
+			pt_error_return(regs, -err);
+		else
+			pt_succ_return(regs, 0);
 		goto out_tsk;
 	}
+	}
 flush_and_out:
 	{
 		unsigned long va;
@@ -612,7 +617,8 @@
 		return;
 	if (!(current->ptrace & PT_PTRACED))
 		return;
-	current->exit_code = SIGTRAP;
+	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+					? 0x80 : 0);
 	current->state = TASK_STOPPED;
 	notify_parent(current, SIGCHLD);
 	schedule();
arch/x86_64/ia32/ptrace32.c +2 -12
diff -Nru a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c
@@ -185,17 +185,6 @@
 	__u32 val;
 
 	switch (request) { 
-	case PTRACE_TRACEME:
-	case PTRACE_ATTACH:
-	case PTRACE_SYSCALL:
-	case PTRACE_CONT:
-	case PTRACE_KILL:
-	case PTRACE_SINGLESTEP:
-	case PTRACE_DETACH:
-	case PTRACE_SETOPTIONS:
-		ret = sys_ptrace(request, pid, addr, data); 
-		return ret;
-
 	case PTRACE_PEEKTEXT:
 	case PTRACE_PEEKDATA:
 	case PTRACE_POKEDATA:
@@ -211,7 +200,8 @@
 		break;
 		
 	default:
-		return -EIO;
+		ret = sys_ptrace(request, pid, addr, data); 
+		return ret;
 	} 
 
 	child = find_target(request, pid, &ret);
arch/x86_64/kernel/ptrace.c +1 -10
diff -Nru a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
@@ -405,17 +405,8 @@
 		break;
 	}
 
-	case PTRACE_SETOPTIONS: {
-		if (data & PTRACE_O_TRACESYSGOOD)
-			child->ptrace |= PT_TRACESYSGOOD;
-		else
-			child->ptrace &= ~PT_TRACESYSGOOD;
-		ret = 0;
-		break;
-	}
-
 	default:
-		ret = -EIO;
+		ret = ptrace_request(child, request, addr, data);
 		break;
 	}
 out_tsk:
include/asm-arm/ptrace.h +1 -4
diff -Nru a/include/asm-arm/ptrace.h b/include/asm-arm/ptrace.h
@@ -6,10 +6,7 @@
 #define PTRACE_GETFPREGS	14
 #define PTRACE_SETFPREGS	15
 
-#define PTRACE_SETOPTIONS	21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD	0x00000001
+#define PTRACE_OLDSETOPTIONS	21
 
 #include <asm/proc/ptrace.h>
 
include/asm-i386/ptrace.h +1 -4
diff -Nru a/include/asm-i386/ptrace.h b/include/asm-i386/ptrace.h
@@ -49,10 +49,7 @@
 #define PTRACE_GETFPXREGS         18
 #define PTRACE_SETFPXREGS         19
 
-#define PTRACE_SETOPTIONS         21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD     0x00000001
+#define PTRACE_OLDSETOPTIONS         21
 
 #ifdef __KERNEL__
 #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs))
include/asm-ia64/ptrace.h +1 -4
diff -Nru a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h
@@ -287,9 +287,6 @@
 #define PTRACE_GETREGS		18	/* get all registers (pt_all_user_regs) in one shot */
 #define PTRACE_SETREGS		19	/* set all registers (pt_all_user_regs) in one shot */
 
-#define PTRACE_SETOPTIONS	21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD	0x00000001
+#define PTRACE_OLDSETOPTIONS	21
 
 #endif /* _ASM_IA64_PTRACE_H */
include/asm-mips/ptrace.h +1 -4
diff -Nru a/include/asm-mips/ptrace.h b/include/asm-mips/ptrace.h
@@ -59,10 +59,7 @@
 /* #define PTRACE_GETFPXREGS		18 */
 /* #define PTRACE_SETFPXREGS		19 */
 
-#define PTRACE_SETOPTIONS	21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD	0x00000001
+#define PTRACE_OLDSETOPTIONS	21
 
 #ifdef _LANGUAGE_ASSEMBLY
 #include <asm/offset.h>
include/asm-mips64/ptrace.h +1 -4
diff -Nru a/include/asm-mips64/ptrace.h b/include/asm-mips64/ptrace.h
@@ -64,10 +64,7 @@
 /* #define PTRACE_GETFPXREGS		18 */
 /* #define PTRACE_SETFPXREGS		19 */
 
-#define PTRACE_SETOPTIONS	21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD	0x00000001
+#define PTRACE_OLDSETOPTIONS	21
 
 #ifdef _LANGUAGE_ASSEMBLY
 #include <asm/offset.h>
include/asm-s390/ptrace.h +1 -4
diff -Nru a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h
@@ -105,10 +105,7 @@
 
 #define STACK_FRAME_OVERHEAD	96	/* size of minimum stack frame */
 
-#define PTRACE_SETOPTIONS         21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD     0x00000001
+#define PTRACE_OLDSETOPTIONS         21
 
 #ifndef __ASSEMBLY__
 #include <linux/config.h>
include/asm-s390x/ptrace.h +1 -4
diff -Nru a/include/asm-s390x/ptrace.h b/include/asm-s390x/ptrace.h
@@ -85,10 +85,7 @@
 
 #define STACK_FRAME_OVERHEAD    160      /* size of minimum stack frame */
 
-#define PTRACE_SETOPTIONS         21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD     0x00000001
+#define PTRACE_OLDSETOPTIONS         21
 
 #ifndef __ASSEMBLY__
 #include <linux/config.h>
include/asm-sh/ptrace.h +1 -4
diff -Nru a/include/asm-sh/ptrace.h b/include/asm-sh/ptrace.h
@@ -44,10 +44,7 @@
 #define REG_XDREG14	47
 #define REG_FPSCR	48
 
-#define PTRACE_SETOPTIONS         21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD     0x00000001
+#define PTRACE_OLDSETOPTIONS         21
 
 /*
  * This struct defines the way the registers are stored on the
include/asm-x86_64/ptrace.h +1 -4
diff -Nru a/include/asm-x86_64/ptrace.h b/include/asm-x86_64/ptrace.h
@@ -32,10 +32,7 @@
 /* top of stack page */ 
 #define FRAME_SIZE 168
 
-#define PTRACE_SETOPTIONS         21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD     0x00000001
+#define PTRACE_OLDSETOPTIONS         21
 
 /* Dummy values for ptrace */ 
 #define FS 1000 
include/linux/ptrace.h +7 -0
diff -Nru a/include/linux/ptrace.h b/include/linux/ptrace.h
@@ -23,6 +23,12 @@
 
 #define PTRACE_SYSCALL		  24
 
+/* 0x4200-0x4300 are reserved for architecture-independent additions.  */
+#define PTRACE_SETOPTIONS	0x4200
+
+/* options set using PTRACE_SETOPTIONS */
+#define PTRACE_O_TRACESYSGOOD	0x00000001
+
 #include <asm/ptrace.h>
 #include <linux/sched.h>
 
@@ -32,6 +38,7 @@
 extern int ptrace_detach(struct task_struct *, unsigned int);
 extern void ptrace_disable(struct task_struct *);
 extern int ptrace_check_attach(struct task_struct *task, int kill);
+extern int ptrace_request(struct task_struct *child, long request, long addr, long data);
 extern void __ptrace_link(struct task_struct *child,
 				struct task_struct *new_parent);
 extern void __ptrace_unlink(struct task_struct *child);
kernel/ptrace.c +32 -0
diff -Nru a/kernel/ptrace.c b/kernel/ptrace.c
@@ -248,3 +248,35 @@
 	}
 	return copied;
 }
+
+int ptrace_setoptions(struct task_struct *child, long data)
+{
+	if (data & PTRACE_O_TRACESYSGOOD)
+		child->ptrace |= PT_TRACESYSGOOD;
+	else
+		child->ptrace &= ~PT_TRACESYSGOOD;
+
+	if ((data & PTRACE_O_TRACESYSGOOD) != data)
+		return -EINVAL;
+
+	return 0;
+}
+
+int ptrace_request(struct task_struct *child, long request,
+		   long addr, long data)
+{
+	int ret = -EIO;
+
+	switch (request) {
+#ifdef PTRACE_OLDSETOPTIONS
+	case PTRACE_OLDSETOPTIONS:
+#endif
+	case PTRACE_SETOPTIONS:
+		ret = ptrace_setoptions(child, data);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
Signature · 2 lines
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer
#1 lore raw

Here's #2.

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas:
# ChangeSet 1.856 -> 1.857
# arch/i386/kernel/process.c 1.32 -> 1.33
# arch/alpha/kernel/entry.S 1.15.1.2 -> 1.17
# arch/x86_64/kernel/process.c 1.7.1.3 -> 1.9
# include/linux/sched.h 1.94.1.15 -> 1.97
# arch/sparc/kernel/process.c 1.18 -> 1.19
# arch/parisc/kernel/entry.S 1.3.1.1 -> 1.6
# arch/mips64/kernel/process.c 1.4 -> 1.5
# arch/ppc64/kernel/misc.S 1.28 -> 1.29
# arch/mips/kernel/process.c 1.7 -> 1.8
# arch/cris/kernel/entry.S 1.12 -> 1.13
# arch/sparc64/kernel/process.c 1.35 -> 1.36
# arch/ia64/kernel/process.c 1.15.1.3 -> 1.18
# arch/m68k/kernel/process.c 1.10 -> 1.11
# arch/cris/kernel/entryoffsets.c 1.3 -> 1.4
# arch/ppc64/kernel/asm-offsets.c 1.11 -> 1.12
# arch/sh/kernel/process.c 1.12 -> 1.13
# arch/s390x/kernel/process.c 1.10.1.4 -> 1.12
# arch/s390/kernel/process.c 1.12.1.4 -> 1.14
# arch/arm/kernel/process.c 1.20 -> 1.21
# arch/ppc/kernel/misc.S 1.29 -> 1.30
# arch/alpha/kernel/asm-offsets.c 1.6 -> 1.7
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/10/31 [email protected] 1.857
# Merge nevyn.them.org:/nevyn/big/kernel/test/linux-2.5-trace1

# into nevyn.them.org:/nevyn/big/kernel/test/linux-2.5-trace2
# --------------------------------------------
#
diff -Nru a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c
--- a/arch/alpha/kernel/asm-offsets.c	Thu Oct 31 14:02:10 2002
+++ b/arch/alpha/kernel/asm-offsets.c	Thu Oct 31 14:02:10 2002
@@ -22,6 +22,7 @@
 	BLANK();
 	DEFINE(PT_PTRACED, PT_PTRACED);
 	DEFINE(CLONE_VM, CLONE_VM);
+	DEFINE(CLONE_UNTRACED, CLONE_UNTRACED);
 	DEFINE(SIGCHLD, SIGCHLD);
 	BLANK();
 	DEFINE(HAE_CACHE, offsetof(struct alpha_machine_vector, hae_cache));
diff -Nru a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
--- a/arch/alpha/kernel/entry.S	Thu Oct 31 14:02:10 2002
+++ b/arch/alpha/kernel/entry.S	Thu Oct 31 14:02:10 2002
@@ -212,7 +212,7 @@
 	stq	$2, 152($30)		/* HAE */

/* Shuffle FLAGS to the front; add CLONE_VM. */
- ldi $1, CLONE_VM
+ ldi $1, CLONE_VM|CLONE_UNTRACED
or $18, $1, $16
bsr $26, sys_clone

arch/arm/kernel/process.c +1 -1
diff -Nru a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
@@ -403,7 +403,7 @@
 	b	sys_exit					\n\
 1:	"
         : "=r" (__ret)
-        : "Ir" (flags), "I" (CLONE_VM), "r" (fn), "r" (arg)
+        : "Ir" (flags), "r" (CLONE_VM | CLONE_UNTRACED), "r" (fn), "r" (arg)
 	: "r0", "r1", "lr");
 	return __ret;
 }
arch/cris/kernel/entry.S +1 -0
diff -Nru a/arch/cris/kernel/entry.S b/arch/cris/kernel/entry.S
@@ -748,6 +748,7 @@
 	/* r11 is argument 2 to clone, the flags */
 	move.d  $r12, $r11
 	or.w	LCLONE_VM, $r11
+	or.w	LCLONE_UNTRACED, $r11
 
 	/* Save FN for later.  */
 	move.d	$r10, $r12
arch/cris/kernel/entryoffsets.c +1 -0
diff -Nru a/arch/cris/kernel/entryoffsets.c b/arch/cris/kernel/entryoffsets.c
@@ -57,5 +57,6 @@
 
 /* linux/sched.h values - doesn't have an #ifdef __ASSEMBLY__ for these.  */
 VAL (LCLONE_VM, CLONE_VM)
+VAL (LCLONE_UNTRACED, CLONE_UNTRACED)
 
 __asm__ (".endif");
arch/i386/kernel/process.c +1 -1
diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
@@ -224,7 +224,7 @@
 	regs.eflags = 0x286;
 
 	/* Ok, create the new process.. */
-	p = do_fork(flags | CLONE_VM, 0, &regs, 0, NULL);
+	p = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
arch/ia64/kernel/process.c +1 -1
diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
@@ -516,7 +516,7 @@
 	struct task_struct *parent = current;
 	int result, tid;
 
-	tid = clone(flags | CLONE_VM, 0);
+	tid = clone(flags | CLONE_VM | CLONE_UNTRACED, 0);
 	if (parent != current) {
 		result = (*fn)(arg);
 		_exit(result);
arch/m68k/kernel/process.c +1 -1
diff -Nru a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
@@ -152,7 +152,7 @@
 
 	{
 	register long retval __asm__ ("d0");
-	register long clone_arg __asm__ ("d1") = flags | CLONE_VM;
+	register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED;
 
 	retval = __NR_clone;
 	__asm__ __volatile__
arch/mips/kernel/process.c +1 -1
diff -Nru a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
@@ -176,7 +176,7 @@
 		:"=r" (retval)
 		:"i" (__NR_clone), "i" (__NR_exit),
 		 "r" (arg), "r" (fn),
-		 "r" (flags | CLONE_VM)
+		 "r" (flags | CLONE_VM | CLONE_UNTRACED)
 		 /*
 		  * The called subroutine might have destroyed any of the
 		  * at, result, argument or temporary registers ...
arch/mips64/kernel/process.c +1 -1
diff -Nru a/arch/mips64/kernel/process.c b/arch/mips64/kernel/process.c
@@ -167,7 +167,7 @@
 		"1:\tmove\t%0, $2"
 		:"=r" (retval)
 		:"i" (__NR_clone), "i" (__NR_exit), "r" (arg), "r" (fn),
-		 "r" (flags | CLONE_VM)
+		 "r" (flags | CLONE_VM | CLONE_UNTRACED)
 
 		 /* The called subroutine might have destroyed any of the
 		  * at, result, argument or temporary registers ...  */
arch/parisc/kernel/entry.S +3 -1
diff -Nru a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
@@ -515,6 +515,7 @@
 	 */
 
 #define CLONE_VM 0x100	/* Must agree with <linux/sched.h> */
+#define CLONE_UNTRACED 0x00800000
 
 	.export __kernel_thread, code
 	.import do_fork
@@ -531,7 +532,8 @@
 #endif
 	STREG	%r26, PT_GR26(%r1)  /* Store function & argument for child */
 	STREG	%r25, PT_GR25(%r1)
-	ldo	CLONE_VM(%r0), %r26   /* Force CLONE_VM since only init_mm */
+	ldil	L%CLONE_UNTRACED, %r26
+	ldo	CLONE_VM(%r26), %r26   /* Force CLONE_VM since only init_mm */
 	or	%r26, %r24, %r26      /* will have kernel mappings.	 */
 	copy	%r0, %r25
 #ifdef __LP64__
arch/ppc/kernel/misc.S +1 -0
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
@@ -1005,6 +1005,7 @@
 	mr	r30,r3		/* function */
 	mr	r31,r4		/* argument */
 	ori	r3,r5,CLONE_VM	/* flags */
+	oris	r3,r3,CLONE_UNTRACED>>16
 	li	r0,__NR_clone
 	sc
 	cmpi	0,r3,0		/* parent or child? */
arch/ppc64/kernel/asm-offsets.c +1 -0
diff -Nru a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c
@@ -157,6 +157,7 @@
 	DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8);
 
 	DEFINE(CLONE_VM, CLONE_VM);
+	DEFINE(CLONE_UNTRACED, CLONE_UNTRACED);
 
 	return 0;
 }
arch/ppc64/kernel/misc.S +1 -0
diff -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
@@ -486,6 +486,7 @@
 	/* XXX fix this when we optimise syscall entry to not save volatiles */
 	mr	r6,r3		/* function */
 	ori	r3,r5,CLONE_VM	/* flags */
+	oris	r3,r3,(CLONE_UNTRACED>>16)
 	li	r0,__NR_clone
 	sc
 	cmpi	0,r3,0		/* parent or child? */
arch/s390/kernel/process.c +1 -1
diff -Nru a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
@@ -146,7 +146,7 @@
 	regs.orig_gpr2 = -1;
 
 	/* Ok, create the new process.. */
-	p = do_fork(flags | CLONE_VM, 0, &regs, 0, NULL);
+	p = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
arch/s390x/kernel/process.c +1 -1
diff -Nru a/arch/s390x/kernel/process.c b/arch/s390x/kernel/process.c
@@ -143,7 +143,7 @@
 	regs.orig_gpr2 = -1;
 
 	/* Ok, create the new process.. */
-	p = do_fork(flags | CLONE_VM, 0, &regs, 0, NULL);
+	p = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
arch/sh/kernel/process.c +1 -1
diff -Nru a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
@@ -120,7 +120,7 @@
 {	/* Don't use this in BL=1(cli).  Or else, CPU resets! */
 	register unsigned long __sc0 __asm__ ("r0");
 	register unsigned long __sc3 __asm__ ("r3") = __NR_clone;
-	register unsigned long __sc4 __asm__ ("r4") = (long) flags | CLONE_VM;
+	register unsigned long __sc4 __asm__ ("r4") = (long) flags | CLONE_VM | CLONE_UNTRACED;
 	register unsigned long __sc5 __asm__ ("r5") = 0;
 	register unsigned long __sc8 __asm__ ("r8") = (long) arg;
 	register unsigned long __sc9 __asm__ ("r9") = (long) fn;
arch/sparc/kernel/process.c +1 -1
diff -Nru a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
@@ -726,7 +726,7 @@
 			   /* Notreached by child. */
 			   "1: mov %%o0, %0\n\t" :
 			   "=r" (retval) :
-			   "i" (__NR_clone), "r" (flags | CLONE_VM),
+			   "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
 			   "i" (__NR_exit),  "r" (fn), "r" (arg) :
 			   "g1", "g2", "g3", "o0", "o1", "memory", "cc");
 	return retval;
arch/sparc64/kernel/process.c +1 -1
diff -Nru a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
@@ -694,7 +694,7 @@
 			   /* Notreached by child. */
 			   "1:" :
 			   "=r" (retval) :
-			   "i" (__NR_clone), "r" (flags | CLONE_VM),
+			   "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
 			   "i" (__NR_exit),  "r" (fn), "r" (arg) :
 			   "g1", "g2", "g3", "o0", "o1", "memory", "cc");
 	return retval;
arch/x86_64/kernel/process.c +1 -1
diff -Nru a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
@@ -59,7 +59,7 @@
 asmlinkage extern void ret_from_fork(void);
 int sys_arch_prctl(int code, unsigned long addr);
 
-unsigned long kernel_thread_flags = CLONE_VM;
+unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED;
 
 int hlt_counter;
 
include/linux/sched.h +1 -0
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
@@ -51,6 +51,7 @@
 #define CLONE_SETTID	0x00100000	/* write the TID back to userspace */
 #define CLONE_CLEARTID	0x00200000	/* clear the userspace TID */
 #define CLONE_DETACHED	0x00400000	/* parent wants no child-exit signal */
+#define CLONE_UNTRACED  0x00800000	/* set if the tracing process can't force CLONE_PTRACE on this clone */
 
 /*
  * List of flags we want to share for kernel threads,
Signature · 2 lines
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer
#2 lore raw

And the interesting one, #3.

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas:
# ChangeSet 1.857 -> 1.858
# include/linux/sched.h 1.95.1.2 -> 1.98
# kernel/fork.c 1.77.1.12 -> 1.81
# include/linux/ptrace.h 1.4 -> 1.5
# fs/binfmt_aout.c 1.12.1.1 -> 1.14

#	     fs/binfmt_elf.c	1.29    -> 1.30   
#	     kernel/ptrace.c	1.19    -> 1.20   

#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/10/31 [email protected] 1.858
# Merge nevyn.them.org:/nevyn/big/kernel/test/linux-2.5-trace2

# into nevyn.them.org:/nevyn/big/kernel/test/linux-2.5-trace3
# --------------------------------------------
#
diff -Nru a/fs/binfmt_aout.c b/fs/binfmt_aout.c
--- a/fs/binfmt_aout.c	Thu Oct 31 14:02:04 2002
+++ b/fs/binfmt_aout.c	Thu Oct 31 14:02:04 2002
@@ -425,8 +425,12 @@
 	regs->gp = ex.a_gpvalue;
 #endif
 	start_thread(regs, ex.a_entry, current->mm->start_stack);
-	if (current->ptrace & PT_PTRACED)
-		send_sig(SIGTRAP, current, 0);
+	if (unlikely(current->ptrace & PT_PTRACED)) {
+		if (current->ptrace & PT_TRACE_EXEC)
+			ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP);
+		else
+			send_sig(SIGTRAP, current, 0);
+	}
 	return 0;
 }
fs/binfmt_elf.c +6 -2
diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c
@@ -792,8 +792,12 @@
 #endif
 
 	start_thread(regs, elf_entry, bprm->p);
-	if (current->ptrace & PT_PTRACED)
-		send_sig(SIGTRAP, current, 0);
+	if (unlikely(current->ptrace & PT_PTRACED)) {
+		if (current->ptrace & PT_TRACE_EXEC)
+			ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP);
+		else
+			send_sig(SIGTRAP, current, 0);
+	}
 	retval = 0;
 out:
 	return retval;
include/linux/ptrace.h +12 -0
diff -Nru a/include/linux/ptrace.h b/include/linux/ptrace.h
@@ -25,9 +25,20 @@
 
 /* 0x4200-0x4300 are reserved for architecture-independent additions.  */
 #define PTRACE_SETOPTIONS	0x4200
+#define PTRACE_GETEVENTMSG	0x4201
 
 /* options set using PTRACE_SETOPTIONS */
 #define PTRACE_O_TRACESYSGOOD	0x00000001
+#define PTRACE_O_TRACEFORK	0x00000002
+#define PTRACE_O_TRACEVFORK	0x00000004
+#define PTRACE_O_TRACECLONE	0x00000008
+#define PTRACE_O_TRACEEXEC	0x00000010
+
+/* Wait extended result codes for the above trace options.  */
+#define PTRACE_EVENT_FORK	1
+#define PTRACE_EVENT_VFORK	2
+#define PTRACE_EVENT_CLONE	3
+#define PTRACE_EVENT_EXEC	4
 
 #include <asm/ptrace.h>
 #include <linux/sched.h>
@@ -39,6 +50,7 @@
 extern void ptrace_disable(struct task_struct *);
 extern int ptrace_check_attach(struct task_struct *task, int kill);
 extern int ptrace_request(struct task_struct *child, long request, long addr, long data);
+extern void ptrace_notify(int exit_code);
 extern void __ptrace_link(struct task_struct *child,
 				struct task_struct *new_parent);
 extern void __ptrace_unlink(struct task_struct *child);
include/linux/sched.h +6 -0
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
@@ -389,6 +389,8 @@
 	void *journal_info;
 	struct dentry *proc_dentry;
 	struct backing_dev_info *backing_dev_info;
+
+	unsigned long ptrace_message;
 };
 
 extern void __put_task_struct(struct task_struct *tsk);
@@ -427,6 +429,10 @@
 #define PT_DTRACE	0x00000002	/* delayed trace (used on m68k, i386) */
 #define PT_TRACESYSGOOD	0x00000004
 #define PT_PTRACE_CAP	0x00000008	/* ptracer can follow suid-exec */
+#define PT_TRACE_FORK	0x00000010
+#define PT_TRACE_VFORK	0x00000020
+#define PT_TRACE_CLONE	0x00000040
+#define PT_TRACE_EXEC	0x00000080
 
 /*
  * Limit the stack by to some sane default: root can always
kernel/fork.c +29 -0
diff -Nru a/kernel/fork.c b/kernel/fork.c
@@ -943,6 +943,22 @@
 	goto fork_out;
 }
 
+static inline int fork_traceflag (unsigned clone_flags)
+{
+	if (clone_flags & (CLONE_UNTRACED | CLONE_IDLETASK))
+		return 0;
+	else if (clone_flags & CLONE_VFORK) {
+		if (current->ptrace & PT_TRACE_VFORK)
+			return PTRACE_EVENT_VFORK;
+	} else if ((clone_flags & CSIGNAL) != SIGCHLD) {
+		if (current->ptrace & PT_TRACE_CLONE)
+			return PTRACE_EVENT_CLONE;
+	} else if (current->ptrace & PT_TRACE_FORK)
+		return PTRACE_EVENT_FORK;
+
+	return 0;
+}
+
 /*
  *  Ok, this is the main fork-routine.
  *
@@ -956,6 +972,13 @@
 			    int *user_tid)
 {
 	struct task_struct *p;
+	int trace = 0;
+
+	if (unlikely(current->ptrace)) {
+		trace = fork_traceflag (clone_flags);
+		if (trace)
+			clone_flags |= CLONE_PTRACE;
+	}
 
 	p = copy_process(clone_flags, stack_start, regs, stack_size, user_tid);
 	if (!IS_ERR(p)) {
@@ -971,6 +994,12 @@
 
 		wake_up_forked_process(p);		/* do this last */
 		++total_forks;
+
+		if (unlikely (trace)) {
+			current->ptrace_message = (unsigned long) p->pid;
+			ptrace_notify ((trace << 8) | SIGTRAP);
+		}
+
 		if (clone_flags & CLONE_VFORK)
 			wait_for_completion(&vfork);
 		else
kernel/ptrace.c +39 -2

62 lines not on this page · raw message

Signature · 2 lines
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer