This is the mail archive of the cygwin-apps mailing list for the Cygwin 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]

Re: [patch/rebase] Add a rebase database to keep track of DLL addresses


On Jul  2 09:15, Corinna Vinschen wrote:
> On Jul  2 01:14, Charles Wilson wrote:
> > On 6/29/2011 11:36 AM, Corinna Vinschen wrote:
> > > here's a patch which adds a new functionality to rebase.
> > 
> > I think this is a good idea; it's been on the rebase TODO list for some
> > time.  I share cgf's concern about dlls which change their ImageSize,
> > but I haven't had a chance to go thru the patch -- it's a holiday
> > weekend here in the US, and I've got Real Life stuff going on.
> > 
> > I'll take a look next week.
> 
> Thanks.  The answer to your concern is "yes, the code tests that".
> If you have a look into the code next week, you'll be probably
> very happy to see that I added lots of comments to explain what I'm
> doing :)
> 
> Btw., there's one comment in the patch which is accidentally at the
> wrong spot:
> 
>   /* FIXME: This loop only implements the top-down case.  Implement a
>      bottom-up case, too, at one point. */
> 
> The new merge_image_info function basically consists of three loops.
> I put the comment in front of the second loop, but it belongs in front
> of loop 3.  I changed that locally, but it's not worth to send a new
> patch for this, I think.

New patch attached with the following changes:

- I introduced a last minute bug into load_image_info.  Fixed.

- merge_image_info now eliminates duplicate DLLs given on the command
  line.  The previous version only eliminated duplicates if one of them
  was in the database and one of them was on the command line.  However,
  a DLL can easily show up twice on the command line as well.

- print_image_info now also eliminates duplicates and handles the files
  from the database.  It always prints the info for the currently existing
  file, rather than blindly printing the data from the database.

- What's more important, print_image_info now checks for overlapping DLLs
  and prints a "*" after each overlapping DLL.  This gives an easy way to
  chaekc if rebasing is necessary:

    $ rebase -s -i


Corinna


Index: rebase.c
===================================================================
RCS file: /sourceware/projects/cygwin-apps-home/cvsfiles/rebase/rebase.c,v
retrieving revision 1.4
diff -u -p -r1.4 rebase.c
--- rebase.c	29 Jun 2011 14:58:55 -0000	1.4
+++ rebase.c	2 Jul 2011 20:39:45 -0000
@@ -19,20 +19,29 @@
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/param.h>
+#if defined(__CYGWIN__) || defined(__MSYS__)
+#include <sys/cygwin.h>
+#endif
 #include <fcntl.h>
 #include <string.h>
 #include <unistd.h>
 #include <locale.h>
 #include <getopt.h>
 #include <string.h>
+#include <errno.h>
 #include "imagehelper.h"
 
+BOOL save_image_info ();
+BOOL load_image_info ();
+BOOL merge_image_info ();
 BOOL collect_image_info (const char *pathname);
 void print_image_info ();
-BOOL rebase (const char *pathname, ULONG *new_image_base);
+BOOL rebase (const char *pathname, ULONG *new_image_base, BOOL down_flag);
 void parse_args (int argc, char *argv[]);
 unsigned long string_to_ulong (const char *string);
 void usage ();
+void help ();
 BOOL is_rebaseable (const char *pathname);
 FILE *file_list_fopen (const char *file_list);
 char *file_list_fgets (char *buf, int size, FILE *file);
@@ -42,25 +51,49 @@ void version ();
 ULONG image_base = 0;
 BOOL down_flag = FALSE;
 BOOL image_info_flag = FALSE;
+BOOL image_storage_flag = FALSE;
+BOOL force_rebase_flag = FALSE;
 ULONG offset = 0;
 int args_index = 0;
 int verbose = 0;
 const char *file_list = 0;
 const char *stdin_file_list = "-";
 
+const char *progname;
+
+const char IMG_INFO_MAGIC[4] = "rBiI";
+
 ULONG ALLOCATION_SLOT;	/* Allocation granularity. */
 
+typedef struct _img_info_hdr
+{
+  char  magic[4];
+  ULONG base; 
+  ULONG offset; 
+  BOOL  down_flag;
+  ULONG count; 
+} img_info_hdr_t;
+
 typedef struct _img_info
 {
-  const char *name;
+  char *name;
+  ULONG name_size;
   ULONG base;
   ULONG size;
+  ULONG slot_size;
+  struct {
+    unsigned needs_rebasing : 1;
+  } flag;
 } img_info_t;
 
 img_info_t *img_info_list = NULL;
 unsigned int img_info_size = 0;
+unsigned int img_info_rebase_start = 0;
 unsigned int img_info_max_size = 0;
 
+#define IMG_INFO_FILE	"/etc/rebase.image_info"
+char tmp_file[] = "/etc/rebase.image_info.XXXXXX";
+
 #ifdef __CYGWIN__
 ULONG cygwin_dll_image_base = 0;
 ULONG cygwin_dll_image_size = 0;
@@ -75,11 +108,18 @@ main (int argc, char *argv[])
   BOOL status;
 
   setlocale (LC_ALL, "");
+  progname = (progname = strrchr (argv[0], '/')) ? progname + 1 : argv[0];
   parse_args (argc, argv);
-  new_image_base = image_base;
   GetSystemInfo (&si);
   ALLOCATION_SLOT = si.dwAllocationGranularity;
 
+  if (image_storage_flag)
+    {
+      if (load_image_info () < 0)
+      	return 2;
+      img_info_rebase_start = img_info_size;
+    }
+  new_image_base = image_base;
 #ifdef __CYGWIN__
   /* Fetch the Cygwin DLLs data to make sure that DLLs aren't rebased
      into the memory area taken by the Cygwin DLL. */
@@ -94,42 +134,472 @@ main (int argc, char *argv[])
   cygwin_dll_image_size += 3 * ALLOCATION_SLOT + 8 * ALLOCATION_SLOT;
 #endif
 
-  /* Rebase file list, if specified. */
+  /* Collect/Rebase file list, if specified. */
   if (file_list)
     {
-      status = TRUE;
       char filename[MAX_PATH + 2];
       FILE *file = file_list_fopen (file_list);
       if (!file)
-	exit (2);
+	return 2;
 
+      status = TRUE;
       while (file_list_fgets (filename, MAX_PATH + 2, file))
 	{
-	  status = image_info_flag ? collect_image_info (filename)
-				    : rebase (filename, &new_image_base);
+	  status = (image_info_flag || image_storage_flag)
+		   ? collect_image_info (filename)
+		   : rebase (filename, &new_image_base, down_flag);
 	  if (!status)
 	    break;
 	}
 
       file_list_fclose (file);
       if (!status)
-	exit (2);
+	return 2;
     }
 
-  /* Rebase command line arguments. */
+  /* Collect/Rebase command line arguments. */
   for (i = args_index; i < argc; i++)
     {
       const char *filename = argv[i];
-      status = image_info_flag ? collect_image_info (filename)
-				 : rebase (filename, &new_image_base);
+      status = (image_info_flag || image_storage_flag)
+	       ? collect_image_info (filename)
+	       : rebase (filename, &new_image_base, down_flag);
       if (!status)
-	exit (2);
+	return 2;
     }
 
   if (image_info_flag)
     print_image_info ();
+  else if (image_storage_flag && img_info_size > 0)
+    {
+      merge_image_info ();
+      status = TRUE;
+      for (i = 0; i < img_info_size; ++i)
+	if (img_info_list[i].flag.needs_rebasing)
+	  {
+	    new_image_base = img_info_list[i].base;
+	    status = rebase (img_info_list[i].name, &new_image_base, FALSE);
+	    if (status)
+	      img_info_list[i].flag.needs_rebasing = 0;
+	  }
+      if (save_image_info () < 0)
+	return 2;
+    }
+
+  return 0;
+}
+
+int
+img_info_cmp (const void *a, const void *b)
+{
+  ULONG abase = ((img_info_t *) a)->base;
+  ULONG bbase = ((img_info_t *) b)->base;
+
+  if (abase < bbase)
+    return -1;
+  if (abase > bbase)
+    return 1;
+  return strcmp (((img_info_t *) a)->name, ((img_info_t *) b)->name);
+}
+
+int
+img_info_name_cmp (const void *a, const void *b)
+{
+  return strcmp (((img_info_t *) a)->name, ((img_info_t *) b)->name);
+}
+
+int
+save_image_info ()
+{
+  int i, fd;
+  int ret = 0;
+  img_info_hdr_t hdr;
+
+  /* Remove all DLLs which couldn't be rebased from the list before storing
+     it in the database file. */
+  for (i = 0; i < img_info_size; ++i)
+    if (img_info_list[i].flag.needs_rebasing)
+      img_info_list[i--] = img_info_list[--img_info_size];
+  /* Create a temporary file to write to. */
+  fd = mkstemp (tmp_file);
+  if (fd < 0)
+    {
+      fprintf (stderr, "%s: failed to create temporary rebase database: %s\n",
+	       progname, strerror (errno));
+      return -1;
+    }
+  qsort (img_info_list, img_info_size, sizeof (img_info_t), img_info_name_cmp);
+  /* First write the number of entries. */
+  memcpy (hdr.magic, IMG_INFO_MAGIC, 4);
+  hdr.base = image_base;
+  hdr.offset = offset;
+  hdr.down_flag = down_flag;
+  hdr.count = img_info_size;
+  if (write (fd, &hdr, sizeof hdr) < 0)
+    {
+      fprintf (stderr, "%s: failed to write rebase database: %s\n",
+	       progname, strerror (errno));
+      ret = -1;
+    }
+  /* Write the list. */
+  else if (write (fd, img_info_list, img_info_size * sizeof (img_info_t)) < 0)
+    {
+      fprintf (stderr, "%s: failed to write rebase database: %s\n",
+	       progname, strerror (errno));
+      ret = -1;
+    }
+  else
+    {
+      int i;
+
+      /* Write all strings. */
+      for (i = 0; i < img_info_size; ++i)
+	if (write (fd, img_info_list[i].name,
+		   strlen (img_info_list[i].name) + 1) < 0)
+	  {
+	    fprintf (stderr, "%s: failed to write rebase database: %s\n",
+		     progname, strerror (errno));
+	    ret = -1;
+	    break;
+	  }
+    }
+  fchmod (fd, 0660);
+  close (fd);
+  if (ret < 0)
+    unlink (tmp_file);
+  else
+    {
+      if (unlink (IMG_INFO_FILE) < 0 && errno != ENOENT)
+	{
+	  fprintf (stderr,
+		   "%s: failed to remove old rebase database file \"%s\":\n"
+		   "%s\n"
+		   "The new rebase database is stored in \"%s\".\n"
+		   "Manually remove \"%s\" and rename \"%s\" to \"%s\",\n"
+		   "otherwise the new rebase database will be unusable.\n",
+		   progname, IMG_INFO_FILE,
+		   strerror (errno),
+		   tmp_file,
+		   IMG_INFO_FILE, tmp_file, IMG_INFO_FILE);
+	  ret = -1;
+	}
+      else if (rename (tmp_file, IMG_INFO_FILE) < 0)
+	{
+	  fprintf (stderr,
+		   "%s: failed to rename \"%s\" to \"%s\":\n"
+		   "%s\n"
+		   "Manually rename \"%s\" to \"%s\",\n"
+		   "otherwise the new rebase database will be unusable.\n",
+		   progname, tmp_file, IMG_INFO_FILE,
+		   strerror (errno),
+		   tmp_file, IMG_INFO_FILE);
+	  ret = -1;
+	}
+    }
+  return ret;
+}
+
+int
+load_image_info ()
+{
+  int fd;
+  int ret = 0;
+  int i;
+  img_info_hdr_t hdr;
+
+  fd = open (IMG_INFO_FILE, O_RDONLY);
+  if (fd < 0)
+    {
+      /* It's no error if the file doesn't exist.  However, in this case
+	 the -b option is mandatory. */
+      if (errno == ENOENT && image_base)
+      	return 0;
+      fprintf (stderr, "%s: failed to open rebase database \"%s\":\n%s\n",
+	       progname, IMG_INFO_FILE, strerror (errno));
+      return -1;
+    }
+  /* First read the header. */
+  if (read (fd, &hdr, sizeof hdr) < 0)
+    {
+      fprintf (stderr, "%s: failed to read rebase database \"%s\":\n%s\n",
+	       progname, IMG_INFO_FILE, strerror (errno));
+      close (fd);
+      return -1;
+    }
+  /* Check the header. */
+  if (memcmp (hdr.magic, IMG_INFO_MAGIC, 4) != 0)
+    {
+      fprintf (stderr, "%s: \"%s\" is not a valid rebase database.\n",
+	       progname, IMG_INFO_FILE);
+      close (fd);
+      return -1;
+    }
+  /* If no new image base has been specified, use the one from the header. */
+  if (image_base == 0)
+    {
+      image_base = hdr.base;
+      down_flag = hdr.down_flag;
+    }
+  if (offset == 0)
+    offset = hdr.offset;
+  /* Don't enforce rebasing if address and offset are unchanged or taken from
+     the file anyway. */
+  if (image_base == hdr.base && offset == hdr.offset)
+    force_rebase_flag = FALSE;
+  img_info_size = hdr.count;
+  /* Allocate memory for the image list. */
+  if (ret == 0)
+    {
+      img_info_max_size = roundup (img_info_size, 100);
+      img_info_list = (img_info_t *) calloc (img_info_max_size,
+					     sizeof (img_info_t));
+      if (!img_info_list)
+	{
+	  fprintf (stderr, "%s: Out of memory.\n", progname);
+	  ret = -1;
+	}
+    }
+  /* Now read the list. */
+  if (ret == 0
+      && read (fd, img_info_list, img_info_size * sizeof (img_info_t)) < 0)
+    {
+      fprintf (stderr, "%s: failed to read rebase database \"%s\":\n%s\n",
+	       progname, IMG_INFO_FILE, strerror (errno));
+      ret = -1;
+    }
+  /* Make sure all pointers are NULL. */
+  if (ret == 0)
+    for (i = 0; i < img_info_size; ++i)
+      img_info_list[i].name = NULL;
+  /* Eventually read the strings. */
+  if (ret == 0)
+    {
+      for (i = 0; i < img_info_size; ++i)
+	{
+	  img_info_list[i].name = (char *)
+				  malloc (img_info_list[i].name_size);
+	  if (!img_info_list[i].name)
+	    {
+	      fprintf (stderr, "%s: Out of memory.\n", progname);
+	      ret = -1;
+	      break;
+	    }
+	  if (read (fd, img_info_list[i].name,
+		    img_info_list[i].name_size) < 0)
+	    {
+	      fprintf (stderr, "%s: failed to read rebase database \"%s\": "
+		       "%s\n", progname, IMG_INFO_FILE, strerror (errno));
+	      ret = -1;
+	      break;
+	    }
+	}
+    }
+  close (fd);
+  /* On failure, free all allocated memory and set list pointer to NULL. */
+  if (ret < 0)
+    {
+      for (i = 0; i < img_info_size && img_info_list[i].name; ++i)
+	free (img_info_list[i].name);
+      free (img_info_list);
+      img_info_list = NULL;
+      img_info_size = 0;
+      img_info_max_size = 0;
+    }
+  return ret;
+}
+
+int
+merge_image_info ()
+{
+  int i, end;
+  img_info_t *match;
+  ULONG floating_image_base;
+
+  /* Sort new files from command line by name. */
+  qsort (img_info_list + img_info_rebase_start,
+	 img_info_size - img_info_rebase_start, sizeof (img_info_t),
+	 img_info_name_cmp);
+  /* Iterate through new files and eliminate duplicates. */
+  for (i = img_info_rebase_start; i + 1 < img_info_size; ++i)
+    if ((img_info_list[i].name_size == img_info_list[i + 1].name_size
+	 && !strcmp (img_info_list[i].name, img_info_list[i + 1].name))
+#ifdef __CYGWIN__
+	|| !strcmp (img_info_list[i].name, "/usr/bin/cygwin1.dll")
+#endif
+       )
+      {
+	free (img_info_list[i].name);
+	memmove (img_info_list + i, img_info_list + i + 1, 
+		 (img_info_size - i - 1) * sizeof (img_info_t));
+	--img_info_size;
+	--i;
+      }
+  /* Iterate through new files and see if they are already available in
+     existing database. */
+  if (img_info_rebase_start)
+    {
+      for (i = img_info_rebase_start; i < img_info_size; ++i)
+	{
+	  match = bsearch (&img_info_list[i], img_info_list,
+			   img_info_rebase_start, sizeof (img_info_t),
+			   img_info_name_cmp);
+	  if (match)
+	    {
+	      /* We found a match.  Now test if the "new" file is actually
+		 the old file, or if it at least fits into the memory slot
+		 of the old file.  If so, screw the new file into the old slot.
+		 Otherwise set base to 0 to indicate that this DLL needs a new
+		 base address. */
+	      if (match->base != img_info_list[i].base
+		  || match->slot_size < img_info_list[i].slot_size)
+		{
+		  /* Reuse the old address if possible. */
+		  if (match->slot_size < img_info_list[i].slot_size)
+		    match->base = 0;
+		  match->flag.needs_rebasing = 1;
+		}
+	      /* Unconditionally overwrite old with new size. */
+	      match->size = img_info_list[i].size;
+	      match->slot_size = img_info_list[i].slot_size;
+	      /* Remove new entry from array. */
+	      free (img_info_list[i].name);
+	      img_info_list[i--] = img_info_list[--img_info_size];
+	    }
+	  else
+	    /* Not in database yet.  Set base to 0 to choose a new one. */
+	    img_info_list[i].base = 0;
+	}
+      /* After eliminating the duplicates, check if the user requested
+	 a new base address on the command line.  If so, overwrite all
+	 base addresses with 0 and set img_info_rebase_start to 0, to
+	 skip any further test. */
+      if (force_rebase_flag)
+	img_info_rebase_start = 0;
+    }
+  if (!img_info_rebase_start)
+    {
+      /* No database yet or enforcing a new base address.  Set base of all
+	 DLLs to 0. */
+      for (i = 0; i < img_info_size; ++i)
+	img_info_list[i].base = 0;
+    }
 
-  exit (0);
+  /* Now sort the old part of the list by base address. */
+  if (img_info_rebase_start)
+    qsort (img_info_list, img_info_rebase_start, sizeof (img_info_t),
+	   img_info_cmp);
+  /* Perform several tests on the information fetched from the database
+     to match with reality. */
+  for (i = 0; i < img_info_rebase_start; ++i)
+    {
+      ULONG cur_base, cur_size, slot_size;
+
+      /* Files with the needs_rebasing flag set have been checked already. */
+      if (img_info_list[i].flag.needs_rebasing)
+	continue;
+      /* Check if the files in the old list still exist.  Drop non-existant
+	 or unaccessible files. */
+      if (access (img_info_list[i].name, F_OK) == -1
+	  || !GetImageInfos (img_info_list[i].name, &cur_base, &cur_size))
+      	{
+	  free (img_info_list[i].name);
+	  memmove (img_info_list + i, img_info_list + i + 1,
+		   (img_info_size - i - 1) * sizeof (img_info_t));
+	  --img_info_rebase_start;
+	  --img_info_size;
+	  continue;
+	}
+      slot_size = roundup2 (cur_size, ALLOCATION_SLOT);
+      /* If the file has been reinstalled, try to rebase to the same address
+	 in the first place. */
+      if (cur_base != img_info_list[i].base)
+	{
+	  img_info_list[i].flag.needs_rebasing = 1;
+	  /* Set cur_base to the old base to simplify subsequent tests. */
+	  cur_base = img_info_list[i].base;
+	}
+      /* However, if the DLL got bigger and doesn't fit into its slot
+	 anymore, rebase this DLL from scratch. */
+      if (i + 1 < img_info_rebase_start
+	  && cur_base + slot_size + offset >= img_info_list[i + 1].base)
+	img_info_list[i].base = 0;
+      /* Does the file match the base address requirements?  If not,
+	 rebase from scratch. */
+      else if ((down_flag && cur_base + slot_size + offset >= image_base)
+	       || (!down_flag && cur_base < image_base))
+	img_info_list[i].base = 0;
+      /* Unconditionally overwrite old with new size. */
+      img_info_list[i].size = cur_size;
+      img_info_list[i].slot_size = slot_size;
+      /* Make sure all DLLs with base address 0 have the needs_rebasing
+	 flag set. */
+      if (img_info_list[i].base == 0)
+	img_info_list[i].flag.needs_rebasing = 1;
+    }
+  /* The remainder of the function expects img_info_size to be > 0. */
+  if (img_info_size == 0)
+    return 0;
+
+  /* Now sort entire list by base address.  The files with address 0 will
+     be first. */
+  if (!force_rebase_flag)
+    qsort (img_info_list, img_info_size, sizeof (img_info_t), img_info_cmp);
+  /* Try to fit all DLLs with base address 0 into the given list. */
+  /* FIXME: This loop only implements the top-down case.  Implement a
+     bottom-up case, too, at one point. */
+  floating_image_base = image_base;
+  end = img_info_size - 1;
+  while (img_info_list[0].base == 0)
+    {
+      ULONG new_base;
+
+      /* Skip trailing entries as long as there is no hole. */
+       while (img_info_list[end].base + img_info_list[end].slot_size + offset
+	     >= floating_image_base)
+	{
+	  floating_image_base = img_info_list[end].base;
+	  --end;
+	}
+      /* Test if one of the DLLs with address 0 fits into the hole. */
+      for (i = 0, new_base = 0; img_info_list[i].base == 0; ++i, new_base = 0)
+	{
+	  new_base = floating_image_base - img_info_list[i].slot_size - offset;
+	  if (new_base >= img_info_list[end].base
+			  + img_info_list[end].slot_size
+#ifdef __CYGWIN__
+	      /* Don't overlap the Cygwin DLL. */
+	      && (new_base >= cygwin_dll_image_base + cygwin_dll_image_size
+		  || new_base + img_info_list[i].slot_size
+		     <= cygwin_dll_image_base)
+#endif
+	     )
+	    break;
+	}
+      /* Found a match.  Mount into list. */
+      if (new_base)
+	{
+	  img_info_t tmp = img_info_list[i];
+	  tmp.base = new_base;
+	  memmove (img_info_list + i, img_info_list + i + 1,
+		   (end - i) * sizeof (img_info_t));
+	  img_info_list[end] = tmp;
+	  continue;
+	}
+      /* Nothing matches.  Set floating_image_base to the start of the
+	 uppermost DLL at this point and try again. */
+#ifdef __CYGWIN__
+      if (floating_image_base >= cygwin_dll_image_base + cygwin_dll_image_size
+	  && img_info_list[end].base < cygwin_dll_image_base)
+	floating_image_base = cygwin_dll_image_base;
+      else
+#endif
+	{
+	  floating_image_base = img_info_list[end].base;
+	  --end;
+	}
+    }
+
+  return 0;
 }
 
 BOOL
@@ -143,7 +613,7 @@ collect_image_info (const char *pathname
       return TRUE;
     }
 
-  if (img_info_size <= img_info_max_size)
+  if (img_info_size >= img_info_max_size)
     {
       img_info_max_size += 100;
       img_info_list = (img_info_t *) realloc (img_info_list,
@@ -151,45 +621,126 @@ collect_image_info (const char *pathname
 					      * sizeof (img_info_t));
       if (!img_info_list)
 	{
-	  fprintf (stderr, "Out of memory.\n");
+	  fprintf (stderr, "%s: Out of memory.\n", progname);
 	  exit (2);
 	}
     }
 
   if (GetImageInfos (pathname, &img_info_list[img_info_size].base,
 			       &img_info_list[img_info_size].size))
-    img_info_list[img_info_size++].name = strdup (pathname);
+    {
+      img_info_list[img_info_size].slot_size
+	= roundup2 (img_info_list[img_info_size].size, ALLOCATION_SLOT);
+      img_info_list[img_info_size].flag.needs_rebasing = 1;
+      /* This back and forth from POSIX to Win32 is a way to get a full path
+	 more thoroughly.  For instance, the difference between /bin and
+	 /usr/bin will be eliminated. */
+#if defined (__MSYS__)
+      {
+	char w32_path[MAX_PATH];
+	char full_path[MAX_PATH];
+      	cygwin_conv_to_full_win32_path (pathname, w32_path);
+	cygwin_conv_to_full_posix_path (w32_path, full_path);
+	img_info_list[img_info_size].name = strdup (full_path);
+	img_info_list[img_info_size].name_size = strlen (full_path) + 1;
+      }
+#elif defined (__CYGWIN__)
+      {
+	PWSTR w32_path = cygwin_create_path (CCP_POSIX_TO_WIN_W, pathname);
+	img_info_list[img_info_size].name
+	  = cygwin_create_path (CCP_WIN_W_TO_POSIX, w32_path);
+	free (w32_path);
+	img_info_list[img_info_size].name_size
+	  = strlen (img_info_list[img_info_size].name) + 1;
+      }
+#else
+      {
+	char full_path[MAX_PATH];
+	GetFullPathName (pathname, MAX_PATH, full_path, NULL);
+	img_info_list[img_info_size].name = strdup (full_path);
+	img_info_list[img_info_size].name_size = strlen (full_path) + 1;
+      }
+#endif
+      ++img_info_size;
+    }
   return TRUE;
 }
 
-int
-img_info_cmp (const void *a, const void *b)
-{
-  ULONG abase = ((img_info_t *) a)->base;
-  ULONG bbase = ((img_info_t *) b)->base;
-
-  if (abase < bbase)
-    return -1;
-  if (abase > bbase)
-    return 1;
-  return strcmp (((img_info_t *) a)->name, ((img_info_t *) b)->name);
-}
-
 void
 print_image_info ()
 {
   unsigned int i;
 
+  /* Sort list by name. */
+  qsort (img_info_list, img_info_size, sizeof (img_info_t), img_info_name_cmp);
+  /* Iterate through list and eliminate duplicates. */
+  for (i = 0; i + 1 < img_info_size; ++i)
+    if (img_info_list[i].name_size == img_info_list[i + 1].name_size
+	&& !strcmp (img_info_list[i].name, img_info_list[i + 1].name))
+      {
+	/* Remove duplicate, but prefer one from the command line over one
+	   from the database, because the one from the command line reflects
+	   the reality, while the database is wishful thinking. */
+	if (img_info_list[i].flag.needs_rebasing == 0)
+	  {
+	    free (img_info_list[i].name);
+	    memmove (img_info_list + i, img_info_list + i + 1, 
+		     (img_info_size - i - 1) * sizeof (img_info_t));
+	  }
+	else
+	  {
+	    free (img_info_list[i + 1].name);
+	    if (i + 2 < img_info_size)
+	      memmove (img_info_list + i + 1, img_info_list + i + 2, 
+		       (img_info_size - i - 2) * sizeof (img_info_t));
+	  }
+	--img_info_size;
+	--i;
+      }
+  /* For entries loaded from database, collect image info to reflect reality.
+     Also, collect_image_info sets needs_rebasing to 1, so reset here. */
+  for (i = 0; i < img_info_size; ++i)
+    {
+      if (img_info_list[i].flag.needs_rebasing == 0)
+	{
+	  ULONG base, size;
+
+	  if (GetImageInfos (img_info_list[i].name, &base, &size))
+	    {
+	      img_info_list[i].base = base;
+	      img_info_list[i].size = size;
+	      img_info_list[i].slot_size
+		= roundup2 (img_info_list[i].size, ALLOCATION_SLOT);
+	    }
+	}
+      else
+	img_info_list[i].flag.needs_rebasing = 0;
+    }
+  /* Now sort by address. */
   qsort (img_info_list, img_info_size, sizeof (img_info_t), img_info_cmp);
   for (i = 0; i < img_info_size; ++i)
-    printf ("%-47s base 0x%08lx size 0x%08lx\n",
-	    img_info_list[i].name,
-	    img_info_list[i].base,
-	    img_info_list[i].size);
+    {
+      int tst;
+      ULONG end = img_info_list[i].base + img_info_list[i].slot_size;
+
+      /* Check for overlap and mark both DLLs. */
+      for (tst = i + 1;
+	   tst < img_info_size && img_info_list[tst].base < end;
+	   ++tst)
+	{
+	  img_info_list[i].flag.needs_rebasing = 1;
+	  img_info_list[tst].flag.needs_rebasing = 1;
+	}
+      printf ("%-45s base 0x%08lx size 0x%08lx %c\n",
+	      img_info_list[i].name,
+	      img_info_list[i].base,
+	      img_info_list[i].size,
+	      img_info_list[i].flag.needs_rebasing ? '*' : ' ');
+    }
 }
 
 BOOL
-rebase (const char *pathname, ULONG *new_image_base)
+rebase (const char *pathname, ULONG *new_image_base, BOOL down_flag)
 {
   ULONG old_image_size, old_image_base, new_image_size, prev_new_image_base;
   BOOL status, status2;
@@ -311,7 +862,7 @@ retry:
 void
 parse_args (int argc, char *argv[])
 {
-  const char *anOptions = "b:dio:T:vV";
+  const char *anOptions = "b:dhio:sT:vV";
   int anOption = 0;
 
   while ((anOption = getopt (argc, argv, anOptions)) != -1)
@@ -320,6 +871,7 @@ parse_args (int argc, char *argv[])
 	{
 	case 'b':
 	  image_base = string_to_ulong (optarg);
+	  force_rebase_flag = TRUE;
 	  break;
 	case 'd':
 	  down_flag = TRUE;
@@ -329,6 +881,12 @@ parse_args (int argc, char *argv[])
 	  break;
 	case 'o':
 	  offset = string_to_ulong (optarg);
+	  force_rebase_flag = TRUE;
+	  break;
+	case 's':
+	  image_storage_flag = TRUE;
+	  /* FIXME: For now enforce top-down rebasing when using the database.*/
+	  down_flag = TRUE;
 	  break;
 	case 'T':
 	  file_list = optarg;
@@ -336,6 +894,10 @@ parse_args (int argc, char *argv[])
 	case 'v':
 	  verbose = TRUE;
 	  break;
+	case 'h':
+	  help ();
+	  exit (1);
+	  break;
 	case 'V':
 	  version ();
 	  exit (1);
@@ -347,7 +909,7 @@ parse_args (int argc, char *argv[])
 	}
     }
 
-  if ((image_base == 0 && !image_info_flag)
+  if ((image_base == 0 && !image_info_flag && !image_storage_flag)
       || (image_base && image_info_flag))
     {
       usage ();
@@ -369,9 +931,40 @@ void
 usage ()
 {
   fprintf (stderr,
-	   "usage: rebase -b BaseAddress [-Vdv] [-o Offset] "
+	   "usage: %s -b BaseAddress [-Vdfsv] [-o Offset] "
 	   "[-T FileList | -] Files...\n"
-	   "       rebase -i [-T FileList | -] Files...\n");
+	   "       rebase -i [-s][-T FileList | -] Files...\n"
+	   "       rebase -h for full help text\n", progname);
+}
+
+void
+help ()
+{
+  printf ("\
+Usage: %s [OPTIONS] file(s)...\n\
+Rebase PE files, usually DLLs, to a specified address or address range.\n\
+\n\
+  -b BaseAddress     Specifies the base address at which to start rebasing.\n\
+  -s                 Utilize the rebase database to find unused memory slots\n\
+                     to rebase the files on the command line to. (Implies -d).\n\
+                     If -b is given, too, the database gets recreated.\n\
+  -i                 Rather then rebasing, just print the current base\n\
+                     address and size of a file.\n\
+\n\
+  One of the options -b, -s or -i is mandatory.  If no rebase database exists\n\
+  yet, -b is required together with -s.\n\
+\n\
+  -d                 Treat the BaseAddress as upper ceiling and rebase\n\
+                     files top-down from there.  Without this option the\n\
+                     files are rebased from BaseAddress bottom-up.\n\
+  -o Offset          Specify an offset between subsequent rebase addresses.\n\
+                     Default is no offset.\n\
+  -T FileList        Also rebase the files specified in the file \"FileList\".\n\
+                     The format of \"FileList\" is one file per line.\n\
+  -v                 Print some debug output.\n\
+  -V                 Print version info and exit.\n\
+  -h                 This help.\n",
+	  progname);
 }
 
 BOOL
Index: rebaseall.in
===================================================================
RCS file: /sourceware/projects/cygwin-apps-home/cvsfiles/rebase/rebaseall.in,v
retrieving revision 1.3
diff -u -p -r1.3 rebaseall.in
--- rebaseall.in	28 Jun 2011 19:43:19 -0000	1.3
+++ rebaseall.in	2 Jul 2011 20:39:45 -0000
@@ -13,7 +13,7 @@
 #
 # Written by Jason Tishler <jason@tishler.net>
 #
-# $Id: rebaseall.in,v 1.3 2011/06/28 19:43:19 corinna Exp $
+# $Id: rebaseall.in,v 1.2 2011/06/21 15:40:10 corinna Exp $
 #
 
 # Define constants
@@ -46,7 +46,7 @@ cleanup()
 trap cleanup 1 2 15
 
 # Set defaults
-BaseAddress=$DefaultBaseAddress
+BaseAddress=""
 Offset=$DefaultOffset
 Verbose=$DefaultVerbose
 FileList=$DefaultFileList
@@ -82,6 +82,17 @@ do
     esac
 done
 
+# Check if rebase database already exists.
+database_exists="no"
+[ -f "/etc/rebase.image_info" ] && database_exists="yes"
+
+# If BaseAddress has not been specified, and the rebase database doesn't exist
+# yet, set BaseAddress to default.
+if [ -z "${BaseAddress}" -a "${database_exists}" != "yes" ]
+then
+  BaseAddress=$DefaultBaseAddress
+fi
+
 # Set temp directory
 TmpDir="${TMP:-${TEMP:-/tmp}}"
 
@@ -120,8 +131,12 @@ then
     cat "$FileList" >>"$TmpFile"
 fi
 
-# Rebase files
-rebase $Verbose -d -b $BaseAddress -o $Offset -T "$TmpFile"
+if [ -z "${BaseAddress}" ]
+then
+  ./rebase $Verbose -s -T "$TmpFile"
+else
+  ./rebase $Verbose -s -b $BaseAddress -o $Offset -T "$TmpFile"
+fi
 ExitCode=$?
 
 # Clean up


-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat


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