// no rescheduling, no malloc calls, and no new stack segments.
// The calls to RawSyscall are okay because they are assembly
// functions that do not grow the stack.
-func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, dir *byte, fd []int, pipe int)
+func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, traceme bool, dir *byte, fd []int, pipe int)
(pid int, err int)
{
// Declare all variables at top in case any
// Fork succeeded, now in child.
+ // Enable tracing if requested.
+ if traceme {
+ r1, r2, err1 = RawSyscall(SYS_PTRACE, uintptr(_PTRACE_TRACEME), 0, 0);
+ if err1 != 0 {
+ goto childerror;
+ }
+ }
+
// Chdir
if dir != nil {
r1, r2, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0);
panic("unreached");
}
-// Combination of fork and exec, careful to be thread safe.
-func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int)
+func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir string, fd []int)
(pid int, err int)
{
var p [2]int;
}
// Kick off child.
- pid, err = forkAndExecInChild(argv0p, argvp, envvp, dirp, fd, p[1]);
+ pid, err = forkAndExecInChild(argv0p, argvp, envvp, traceme, dirp, fd, p[1]);
if err != 0 {
error:
if p[0] >= 0 {
return pid, 0
}
+// Combination of fork and exec, careful to be thread safe.
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int)
+ (pid int, err int)
+{
+ return forkExec(argv0, argv, envv, false, dir, fd);
+}
+
+// PtraceForkExec is like ForkExec, but starts the child in a traced state.
+func PtraceForkExec(argv0 string, argv []string, envv []string, dir string, fd []int)
+ (pid int, err int)
+{
+ return forkExec(argv0, argv, envv, true, dir, fd);
+}
+
// Ordinary exec.
func Exec(argv0 string, argv []string, envv []string) (err int) {
r1, r2, err1 := RawSyscall(SYS_EXECVE,