This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC] Support of Lion (darwin 11)


Hi,

with the latest mac OS X, executables are now pie by default and their load address is random.  This obviously needs to be considered by gdb, and the easiest method is to disable the randomization.

Contrary to other OS, this is done at exec (i.e. posix_spawn) time.  In order to use posix_spawn instead of exec, I added a parameter to fork_inferior.  But to do that, I first slightly changed the fork_inferior code to always use execvp.  I also did some cleanup in this function:  use alloca instead of xmalloc for argv to avoid a memory leak, and moved the code that allocate shell_command within the if (shell) block.  I also factorized the gdb_flush/_exit code used in case on error.

The remaining of the patch is somewhat trivial: adjusting all the calls of fork_inferior (I preferred to pass NULL instead of execvp, because the prototype of the later is somewhat not universal), and doing the real work for darwin.

No regressions on i386 GNU/Linux,
manually tested on Lion.

Ok for trunk ?

Tristan.

2011-09-07  Tristan Gingold  <gingold@adacore.com>

	* fork-child.c (fork_inferior): Add exec_fun parameter.
	Update comment.  Use alloca instead of xmalloc for argv.  Move
	len and shell_command declarations in the block where they are used.
	Call exec_fun or execvp.  Factorize some failure code.
	* inferior.h: Adjust prototype.
	* gnu-nat.c (gnu_create_inferior): Adjsut fork_inferior call.
	* inf-ttrace.c (inf_ttrace_create_inferior): Ditto.
	* inf-ptrace.c (inf_ptrace_create_inferior): Ditto.
	* procfs.c (procfs_create_inferior): Ditto.
	* darwin-nat.c (darwin_execvp): New function.
	(darwin_create_inferior): Use it.

diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index bb173e7..ce947c4 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -115,6 +115,7 @@ escape_bang_in_quoted_argument (const char *shell_file)
    pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
    the arguments to the program.  ENV is the environment vector to
    pass.  SHELL_FILE is the shell file, or NULL if we should pick
+   one.  EXEC_FUN is the exec(2) function to use, or NULL for the default
    one.  */
 
 /* This function is NOT reentrant.  Some of the variables have been
@@ -123,12 +124,12 @@ escape_bang_in_quoted_argument (const char *shell_file)
 int
 fork_inferior (char *exec_file_arg, char *allargs, char **env,
 	       void (*traceme_fun) (void), void (*init_trace_fun) (int),
-	       void (*pre_trace_fun) (void), char *shell_file_arg)
+	       void (*pre_trace_fun) (void), char *shell_file_arg,
+               void (*exec_fun)(const char *file, char * const *argv,
+                                char * const *env))
 {
   int pid;
-  char *shell_command;
   static char default_shell_file[] = SHELL_FILE;
-  int len;
   /* Set debug_fork then attach to the child while it sleeps, to debug.  */
   static int debug_fork = 0;
   /* This is set to the result of setpgrp, which if vforked, will be visible
@@ -162,16 +163,6 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
       shell = 1;
     }
 
-  /* Multiplying the length of exec_file by 4 is to account for the
-     fact that it may expand when quoted; it is a worst-case number
-     based on every character being '.  */
-  len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
-  if (exec_wrapper)
-    len += strlen (exec_wrapper) + 1;
-
-  shell_command = (char *) alloca (len);
-  shell_command[0] = '\0';
-
   if (!shell)
     {
       /* We're going to call execvp.  Create argument vector.
@@ -180,18 +171,29 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
 	 argument.  */
       int argc = (strlen (allargs) + 1) / 2 + 2;
 
-      argv = (char **) xmalloc (argc * sizeof (*argv));
+      argv = (char **) alloca (argc * sizeof (*argv));
       argv[0] = exec_file;
       breakup_args (allargs, &argv[1]);
     }
   else
     {
       /* We're going to call a shell.  */
-
+      char *shell_command;
+      int len;
       char *p;
       int need_to_quote;
       const int escape_bang = escape_bang_in_quoted_argument (shell_file);
 
+      /* Multiplying the length of exec_file by 4 is to account for the
+         fact that it may expand when quoted; it is a worst-case number
+         based on every character being '.  */
+      len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop */ 12;
+      if (exec_wrapper)
+        len += strlen (exec_wrapper) + 1;
+
+      shell_command = (char *) alloca (len);
+      shell_command[0] = '\0';
+
       strcat (shell_command, "exec ");
 
       /* Add any exec wrapper.  That may be a program name with arguments, so
@@ -257,6 +259,16 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
 
       strcat (shell_command, " ");
       strcat (shell_command, allargs);
+
+      /* If we decided above to start up with a shell, we exec the
+	 shell, "-c" says to interpret the next arg as a shell command
+	 to execute, and this command is "exec <target-program>
+	 <args>".  */
+      argv = (char **) alloca (4 * sizeof (char *));
+      argv[0] = shell_file;
+      argv[1] = "-c";
+      argv[2] = shell_command;
+      argv[3] = (char *) 0;
     }
 
   /* On some systems an exec will fail if the executable is open.  */
@@ -348,29 +360,21 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
          path to find $SHELL.  Rich Pixley says so, and I agree.  */
       environ = env;
 
-      /* If we decided above to start up with a shell, we exec the
-	 shell, "-c" says to interpret the next arg as a shell command
-	 to execute, and this command is "exec <target-program>
-	 <args>".  */
+      if (exec_fun != NULL)
+        (*exec_fun) (argv[0], argv, env);
+      else
+        execvp (argv[0], argv);
+
+      /* If we get here, it's an error.  */
       if (shell)
 	{
-	  execlp (shell_file, shell_file, "-c", shell_command, (char *) 0);
-
-	  /* If we get here, it's an error.  */
 	  fprintf_unfiltered (gdb_stderr, "Cannot exec %s: %s.\n", shell_file,
 			      safe_strerror (errno));
-	  gdb_flush (gdb_stderr);
-	  _exit (0177);
 	}
       else
 	{
-	  /* Otherwise, we directly exec the target program with
-	     execvp.  */
 	  int i;
 
-	  execvp (exec_file, argv);
-
-	  /* If we get here, it's an error.  */
 	  safe_strerror (errno);
 	  fprintf_unfiltered (gdb_stderr, "Cannot exec %s ", exec_file);
 
@@ -383,9 +387,9 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
 	      i++;
 	    }
 	  fprintf_unfiltered (gdb_stderr, ".\n");
-	  gdb_flush (gdb_stderr);
-	  _exit (0177);
 	}
+      gdb_flush (gdb_stderr);
+      _exit (0177);
     }
 
   /* Restore our environment in case a vforked child clob'd it.  */
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 7269694..32f78be 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -2114,7 +2114,8 @@ gnu_create_inferior (struct target_ops *ops,
 
   inf_debug (inf, "creating inferior");
 
-  pid = fork_inferior (exec_file, allargs, env, trace_me, NULL, NULL, NULL);
+  pid = fork_inferior (exec_file, allargs, env, trace_me,
+                       NULL, NULL, NULL, NULL);
 
   /* Attach to the now stopped child, which is actually a shell...  */
   inf_debug (inf, "attaching to child: %d", pid);
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index b5e1744..110e825 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -134,7 +134,7 @@ inf_ptrace_create_inferior (struct target_ops *ops,
     }
 
   pid = fork_inferior (exec_file, allargs, env, inf_ptrace_me, NULL,
-		       NULL, NULL);
+		       NULL, NULL, NULL);
 
   if (! ops_already_pushed)
     discard_cleanups (back_to);
diff --git a/gdb/inf-ttrace.c b/gdb/inf-ttrace.c
index ab075db..0ab6580 100644
--- a/gdb/inf-ttrace.c
+++ b/gdb/inf-ttrace.c
@@ -650,7 +650,7 @@ inf_ttrace_create_inferior (struct target_ops *ops, char *exec_file,
   gdb_assert (inf_ttrace_vfork_ppid == -1);
 
   pid = fork_inferior (exec_file, allargs, env, inf_ttrace_me, NULL,
-		       inf_ttrace_prepare, NULL);
+		       inf_ttrace_prepare, NULL, NULL);
 
   inf_ttrace_him (ops, pid);
 }
diff --git a/gdb/inferior.h b/gdb/inferior.h
index cf747a6..f5794fe 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -189,7 +189,9 @@ extern void terminal_init_inferior_with_pgrp (int pgrp);
 
 extern int fork_inferior (char *, char *, char **,
 			  void (*)(void),
-			  void (*)(int), void (*)(void), char *);
+			  void (*)(int), void (*)(void), char *,
+                          void (*)(const char *,
+                                   char * const *, char * const *));
 
 
 extern void startup_inferior (int);
diff --git a/gdb/procfs.c b/gdb/procfs.c
index 917e122..871dd47 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -4915,7 +4915,7 @@ procfs_create_inferior (struct target_ops *ops, char *exec_file,
     }
 
   pid = fork_inferior (exec_file, allargs, env, procfs_set_exec_trap,
-		       NULL, NULL, shell_file);
+		       NULL, NULL, shell_file, NULL);
 
   procfs_init_inferior (ops, pid);
 }
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index 06a1558..4e5eb42 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -53,6 +53,7 @@
 #include <sys/proc.h>
 #include <libproc.h>
 #include <sys/syscall.h>
+#include <spawn.h>
 
 #include <mach/mach_error.h>
 #include <mach/mach_vm.h>
@@ -1507,12 +1508,47 @@ darwin_ptrace_him (int pid)
 }
 
 static void
+darwin_execvp (const char *file, char * const argv[], char * const env[])
+{
+  posix_spawnattr_t attr;
+  short flags;
+  int retval;
+
+  retval = posix_spawnattr_init (&attr);
+  if (retval != 0)
+    {
+      warning ("Couldn't initialize attributes for posix_spawn, error: %d",
+               retval);
+      return;
+    }
+
+  /* Do like execve: replace the image.  */
+  flags = POSIX_SPAWN_SETEXEC;
+
+  /* Disable ASLR.  The constant doesn't look to be available outside the
+     kernel include files.  */
+#ifndef _POSIX_SPAWN_DISABLE_ASLR
+#define _POSIX_SPAWN_DISABLE_ASLR	0x0100
+#endif
+  flags |= _POSIX_SPAWN_DISABLE_ASLR;
+  retval = posix_spawnattr_setflags (&attr, flags);
+  if (retval != 0)
+    {
+      warning ("Couldn't set the posix_spawn flags, error: %d",
+               retval);
+      return;
+    }
+
+  posix_spawnp (NULL, argv[0], NULL, &attr, argv, env);
+}
+
+static void
 darwin_create_inferior (struct target_ops *ops, char *exec_file,
 			char *allargs, char **env, int from_tty)
 {
   /* Do the hard work.  */
   fork_inferior (exec_file, allargs, env, darwin_ptrace_me, darwin_ptrace_him,
-		 darwin_pre_ptrace, NULL);
+		 darwin_pre_ptrace, NULL, darwin_execvp);
 
   /* Return now in case of error.  */
   if (ptid_equal (inferior_ptid, null_ptid))


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]