This is the mail archive of the
cygwin-apps
mailing list for the Cygwin project.
Re: [patch/rebase] Make rebase 64 bit capable, take 2
On Jul 10 16:00, Corinna Vinschen wrote:
> Here's my patch. After some brooding I decided that a -4 and -8 option
> is the way to go. -4 is default if rebase is a 32 bit exe, -8 is default
> if rebase is a 64 bit executable. While I was at it, I also added
> long options to rebase. The corresponding long options to -4 and -8 are,
> who would have guessed, --32 and --64 :)
>
> Whatever you do now, you're either running in 32 bit mode or in 64 bit
> mode. This implementation does not allow to mix DLLs of both types in
> the same call. I renamed the databases to rebase.db.i386 and
> rebase.db.x86_64, that should be pretty self-explanatory. Rather than
> using different megic numbers I decided to add a WORD which keeps the
> machine type as defined for the executable headers as well.
>
> I also made a couple of changes so that rebase builds on mingw64. A few
> more changes for mingw and msys are still required.
>
> rebaseall got another small kick, so you can specify the -4 and
> -8 options as well. `uname -m` is used to find out the default.
>
> Please have a look and give it a try.
Update:
I didn't like the way how messages about skipping files are printed.
That's not well covered by the --verbose option, so I decided to print
the "skipped because" messages, unless the --quite option is given.
Corinna
* Makefile.in (DEFS): Add define for sysconfdir.
(edit): Add substitute expression for sysconfdir.
* rebase.c: Implement rebase database.
(roundup): Define.
(roundup2): Define.
(machine): New global variable to keep requested machine type.
(image_storage_flag): New flag.
(force_rebase_flag): Ditto.
(quite): Ditto.
(verbose): Convert to type BOOL.
(progname): New variable for printing application name in error
output.
(img_info_hdr_t): New type.
(img_info_t): De-const name. Add name_size, slot_size, and
flag members.
(IMG_INFO_FILE_I386): Define database name for i386 systems.
(IMG_INFO_FILE_AMD64): Define database name for x86_64 systems.
(IMG_INFO_FILE): Define default database name.
(gen_progname): New function to initialize progname.
(main): Call gen_progname. Only fetch Cygwin DLL info in
32 bit mode for now. Always collect file info, then rebase
dependent on mode. In database mode, call load_image_info,
collect_image_info, merge_image_info, and save_image_info.
(img_info_name_cmp): New comparison function.
(save_image_info): New function to save rebase database.
(load_image_info): New function to load rebase database.
(merge_image_info): New function to compute rebase values.
(collect_image_info): Fix typo in condition. Check for rebaseable
file here. Convert given filename to absolute pathname.
(print_image_info): Revamp to take database into account. Add
collision information.
(rebase): Take down_flag as parameter to allow influencing the
algorithm from caller. Drop call to is_rebaseable here.
(long_options): New option array for getopt_long.
(short_options): Hold short options.
(parse_args): Drop anOptions. Rename anOption to opt. Call
getopt_long. Handle all new flags.
(usage): Change to reflect new flags.
(help): New function.
* rebaseall.in: Use database mode. Add -4 and -8 options and
handle 32 and 64 bit modes.
Index: Makefile.in
===================================================================
RCS file: /sourceware/projects/cygwin-apps-home/cvsfiles/rebase/Makefile.in,v
retrieving revision 1.5
diff -u -p -r1.5 Makefile.in
--- Makefile.in 7 Jul 2011 16:08:37 -0000 1.5
+++ Makefile.in 10 Jul 2011 14:58:58 -0000
@@ -1,4 +1,4 @@
-# $Id: Makefile.in,v 1.5 2011/07/07 16:08:37 corinna Exp $
+# $Id: Makefile.in,v 1.4 2011/06/28 19:43:19 corinna Exp $
# @configure_input@
# Makefile for rebase
@@ -56,7 +56,7 @@ FGREP = @FGREP@
ASH = @ASH@
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(srcdir)/imagehelper
-DEFS = @DEFS@ -DVERSION='"$(PACKAGE_VERSION)"' -DLIB_VERSION='"$(LIB_VERSION)"'
+DEFS = @DEFS@ -DVERSION='"$(PACKAGE_VERSION)"' -DLIB_VERSION='"$(LIB_VERSION)"' -DSYSCONFDIR='"$(sysconfdir)"'
override CFLAGS+=-Wall -Werror
override CXXFLAGS+=-Wall -Werror
@@ -109,6 +109,7 @@ getopt_long.$(O):: getopt_long.c getopt.
# bindir and friends in your shell scripts"
edit = sed \
-e 's|@bindir[@]|$(bindir)|g' \
+ -e 's|@sysconfdir[@]|$(sysconfdir)|g' \
-e 's|@pkgdatadir[@]|$(pkgdatadir)|g' \
-e 's|@prefix[@]|$(prefix)|g' \
-e 's|@exec_prefix[@]|$(exec_prefix)|g' \
Index: rebase.c
===================================================================
RCS file: /sourceware/projects/cygwin-apps-home/cvsfiles/rebase/rebase.c,v
retrieving revision 1.5
diff -u -p -r1.5 rebase.c
--- rebase.c 8 Jul 2011 08:22:59 -0000 1.5
+++ rebase.c 10 Jul 2011 14:58:58 -0000
@@ -19,6 +19,9 @@
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
+#if defined(__CYGWIN__) || defined(__MSYS__)
+#include <sys/cygwin.h>
+#endif
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
@@ -26,125 +29,709 @@
#include <getopt.h>
#include <string.h>
#include <inttypes.h>
+#include <errno.h>
#include "imagehelper.h"
+#define roundup(x,y) ((((x) + ((y) - 1)) / (y)) * (y))
+#define roundup2(x,y) (((x) + (y) - 1) & ~((y) - 1))
+
+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, ULONG64 *new_image_base);
+BOOL rebase (const char *pathname, ULONG64 *new_image_base, BOOL down_flag);
void parse_args (int argc, char *argv[]);
unsigned long long string_to_ulonglong (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);
int file_list_fclose (FILE *file);
void version ();
+#ifdef __x86_64__
+WORD machine = IMAGE_FILE_MACHINE_AMD64;
+#else
+WORD machine = IMAGE_FILE_MACHINE_I386;
+#endif
ULONG64 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;
+BOOL verbose = FALSE;
+BOOL quiet = FALSE;
const char *file_list = 0;
const char *stdin_file_list = "-";
+const char *progname;
+
+const char IMG_INFO_MAGIC[4] = "rBiI";
+const ULONG IMG_INFO_VERSION = 1;
+
ULONG ALLOCATION_SLOT; /* Allocation granularity. */
+#pragma pack (push, 4)
+
+typedef struct _img_info_hdr
+{
+ CHAR magic[4]; /* Always IMG_INFO_MAGIC. */
+ WORD machine; /* IMAGE_FILE_MACHINE_I386/IMAGE_FILE_MACHINE_AMD64 */
+ WORD version; /* Database version, always set to IMG_INFO_VERSION. */
+ ULONG64 base; /* Base address (-b) used to generate database. */
+ ULONG offset; /* Offset (-o) used to generate database. */
+ BOOL down_flag; /* Always TRUE right now. */
+ ULONG count; /* Number of img_info_t entries following header. */
+} img_info_hdr_t;
+
typedef struct _img_info
{
- const char *name;
- ULONG64 base;
- ULONG size;
+ union {
+ PCHAR name; /* Absolute path to DLL. The strings are stored */
+ ULONG64 _filler; /* right after the img_info_t table, in the same */
+ }; /* order as the img_info_t entries. */
+ ULONG name_size; /* Length of name string including trailing NUL. */
+ ULONG64 base; /* Base address the DLL has been rebased to. */
+ ULONG size; /* Size of the DLL at rebased time. */
+ ULONG slot_size; /* Size of the DLL rounded to allocation granularity.*/
+ struct { /* Flags */
+ unsigned needs_rebasing : 1; /* Set to 0 in the database. Used only */
+ /* while rebasing. */
+ } flag;
} img_info_t;
+#pragma pack (pop)
+
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;
+#if !defined (__CYGWIN__) && !defined (__MSYS__)
+#undef SYSCONFDIR
+#define SYSCONFDIR "/../etc"
+#endif
+#define IMG_INFO_FILE_I386 SYSCONFDIR "/rebase.db.i386"
+#define IMG_INFO_FILE_AMD64 SYSCONFDIR "/rebase.db.x86_64"
+#ifdef __x86_64__
+#define IMG_INFO_FILE IMG_INFO_FILE_AMD64
+#else
+#define IMG_INFO_FILE IMG_INFO_FILE_I386
+#endif
+char *db_file = IMG_INFO_FILE;
+char tmp_file[] = SYSCONFDIR "/rebase.db.XXXXXX";
+
#ifdef __CYGWIN__
ULONG64 cygwin_dll_image_base = 0;
ULONG cygwin_dll_image_size = 0;
#endif
+void
+gen_progname (const char *arg0)
+{
+ char *p;
+
+ p = strrchr (arg0, '/');
+ if (!p)
+ p = strrchr (arg0, '\\');
+ progname = p ? p + 1 : arg0;
+ if ((p = strrchr (progname, '.')) && !strcmp (p, ".exe"))
+ *p = 0;
+}
+
int
main (int argc, char *argv[])
{
- ULONG64 new_image_base = 0;
int i = 0;
SYSTEM_INFO si;
BOOL status;
setlocale (LC_ALL, "");
+ gen_progname (argv[0]);
parse_args (argc, argv);
- new_image_base = image_base;
GetSystemInfo (&si);
ALLOCATION_SLOT = si.dwAllocationGranularity;
+ /* If database support has been requested, load database. */
+ if (image_storage_flag)
+ {
+ if (load_image_info () < 0)
+ return 2;
+ img_info_rebase_start = img_info_size;
+ }
+
#ifdef __CYGWIN__
- /* Fetch the Cygwin DLLs data to make sure that DLLs aren't rebased
- into the memory area taken by the Cygwin DLL. */
- GetImageInfos64 ("/bin/cygwin1.dll", NULL,
- &cygwin_dll_image_base, &cygwin_dll_image_size);
- /* Take the three shared memory areas preceeding the DLL into account. */
- cygwin_dll_image_base -= 3 * ALLOCATION_SLOT;
- /* Add a slack of 8 * 64K at the end of the Cygwin DLL. This leave a
- bit of room to install newer, bigger Cygwin DLLs, as well as room to
- install non-optimized DLLs for debugging purposes. Otherwise the
- slightest change might break fork again :-P */
- cygwin_dll_image_size += 3 * ALLOCATION_SLOT + 8 * ALLOCATION_SLOT;
+ if (machine == IMAGE_FILE_MACHINE_I386)
+ {
+ /* Fetch the Cygwin DLLs data to make sure that DLLs aren't rebased
+ into the memory area taken by the Cygwin DLL. */
+ GetImageInfos64 ("/bin/cygwin1.dll", NULL,
+ &cygwin_dll_image_base, &cygwin_dll_image_size);
+ /* Take the three shared memory areas preceeding the DLL into account. */
+ cygwin_dll_image_base -= 3 * ALLOCATION_SLOT;
+ /* Add a slack of 8 * 64K at the end of the Cygwin DLL. This leave a
+ bit of room to install newer, bigger Cygwin DLLs, as well as room to
+ install non-optimized DLLs for debugging purposes. Otherwise the
+ slightest change might break fork again :-P */
+ cygwin_dll_image_size += 3 * ALLOCATION_SLOT + 8 * ALLOCATION_SLOT;
+ }
#endif
- /* Rebase file list, if specified. */
+ /* Collect 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 = collect_image_info (filename);
if (!status)
break;
}
file_list_fclose (file);
if (!status)
- exit (2);
+ return 2;
}
- /* Rebase command line arguments. */
+ /* Collect 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 = collect_image_info (filename);
if (!status)
- exit (2);
+ return 2;
}
+ /* Nothing to do? */
+ if (img_info_size == 0)
+ return 0;
+
+ /* Check what we have to do and do it. */
if (image_info_flag)
- print_image_info ();
+ {
+ /* Print. */
+ print_image_info ();
+ }
+ else if (!image_storage_flag)
+ {
+ /* Rebase. */
+ ULONG64 new_image_base = image_base;
+ for (i = 0; i < img_info_size; ++i)
+ {
+ status = rebase (img_info_list[i].name, &new_image_base, down_flag);
+ if (!status)
+ return 2;
+ }
+ }
+ else
+ {
+ /* Rebase with database support. */
+ merge_image_info ();
+ status = TRUE;
+ for (i = 0; i < img_info_size; ++i)
+ if (img_info_list[i].flag.needs_rebasing)
+ {
+ ULONG64 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)
+{
+ ULONG64 abase = ((img_info_t *) a)->base;
+ ULONG64 bbase = ((img_info_t *) b)->base;
- exit (0);
+ 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);
+}
+
+#ifndef __CYGWIN__
+int
+mkstemp (char *name)
+{
+ return open (mktemp (name), O_CREAT | O_TRUNC | O_EXCL, 0600);
+}
+#endif
+
+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.machine = machine;
+ hdr.version = IMG_INFO_VERSION;
+ 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;
+ }
+ }
+#ifdef __CYGWIN__
+ fchmod (fd, 0660);
+#else
+ chmod (tmp_file, 0660);
+#endif
+ close (fd);
+ if (ret < 0)
+ unlink (tmp_file);
+ else
+ {
+ if (unlink (db_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, db_file,
+ strerror (errno),
+ tmp_file,
+ db_file, tmp_file, db_file);
+ ret = -1;
+ }
+ else if (rename (tmp_file, db_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, db_file,
+ strerror (errno),
+ tmp_file, db_file);
+ ret = -1;
+ }
+ }
+ return ret;
+}
+
+int
+load_image_info ()
+{
+ int fd;
+ int ret = 0;
+ int i;
+ img_info_hdr_t hdr;
+
+ fd = open (db_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, db_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, db_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, db_file);
+ close (fd);
+ return -1;
+ }
+ if (hdr.machine != machine)
+ {
+ if (hdr.machine == IMAGE_FILE_MACHINE_I386)
+ fprintf (stderr,
+"%s: \"%s\" is a database file for 32 bit DLLs but\n"
+"I'm started to handle 64 bit DLLs. If you want to handle 32 bit DLLs,\n"
+"use the -4 option.\n", progname, db_file);
+ else if (hdr.machine == IMAGE_FILE_MACHINE_AMD64)
+ fprintf (stderr,
+"%s: \"%s\" is a database file for 64 bit DLLs but\n"
+"I'm started to handle 32 bit DLLs. If you want to handle 64 bit DLLs,\n"
+"use the -8 option.\n", progname, db_file);
+ else
+ fprintf (stderr, "%s: \"%s\" is a database file for a machine type\n"
+ "I don't know about.", progname, db_file);
+ close (fd);
+ return -1;
+ }
+ if (hdr.version != IMG_INFO_VERSION)
+ {
+ fprintf (stderr, "%s: \"%s\" is a version %u rebase database.\n"
+ "I can only handle versions up to %lu.\n",
+ progname, db_file, hdr.version, IMG_INFO_VERSION);
+ 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, db_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, db_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;
+ ULONG64 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;
+ }
+
+ /* 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)
+ {
+ ULONG64 cur_base;
+ ULONG 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
+ || !GetImageInfos64 (img_info_list[i].name, NULL,
+ &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)
+ {
+ ULONG64 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
collect_image_info (const char *pathname)
{
+ BOOL ret;
+ WORD dll_machine;
+
/* Skip if file does not exist to prevent ReBaseImage() from using it's
stupid search algorithm (e.g, PATH, etc.). */
if (access (pathname, F_OK) == -1)
{
- fprintf (stderr, "%s: skipped because nonexistent\n", pathname);
+ if (!quiet)
+ fprintf (stderr, "%s: skipped because nonexistent.\n", pathname);
return TRUE;
}
- if (img_info_size <= img_info_max_size)
+ /* Skip if not rebaseable, but only if we're collecting for rebasing,
+ not if we're collecting for printing only. */
+ if (!image_info_flag && !is_rebaseable (pathname))
+ {
+ if (!quiet)
+ fprintf (stderr, "%s: skipped because not rebaseable\n", pathname);
+ return TRUE;
+ }
+
+ if (img_info_size >= img_info_max_size)
{
img_info_max_size += 100;
img_info_list = (img_info_t *) realloc (img_info_list,
@@ -152,46 +739,152 @@ collect_image_info (const char *pathname
* sizeof (img_info_t));
if (!img_info_list)
{
- fprintf (stderr, "Out of memory.\n");
- exit (2);
+ fprintf (stderr, "%s: Out of memory.\n", progname);
+ return FALSE;
}
}
- if (GetImageInfos64 (pathname, NULL,
- &img_info_list[img_info_size].base,
- &img_info_list[img_info_size].size))
- img_info_list[img_info_size++].name = strdup (pathname);
+ ret = GetImageInfos64 (pathname, &dll_machine,
+ &img_info_list[img_info_size].base,
+ &img_info_list[img_info_size].size);
+ if (!ret)
+ {
+ if (!quiet)
+ fprintf (stderr, "%s: skipped because file info unreadable.\n",
+ pathname);
+ return TRUE;
+ }
+ if (dll_machine != machine)
+ {
+ if (!quiet)
+ fprintf (stderr, "%s: skipped because wrong machine type.\n",
+ pathname);
+ return TRUE;
+ }
+ 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);
+ if (!w32_path)
+ {
+ fprintf (stderr, "%s: Out of memory.\n", progname);
+ return FALSE;
+ }
+ img_info_list[img_info_size].name
+ = cygwin_create_path (CCP_WIN_W_TO_POSIX, w32_path);
+ if (!img_info_list[img_info_size].name)
+ {
+ fprintf (stderr, "%s: Out of memory.\n", progname);
+ return FALSE;
+ }
+ 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)
-{
- ULONG64 abase = ((img_info_t *) a)->base;
- ULONG64 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)
+ {
+ ULONG64 base;
+ ULONG size;
+
+ if (GetImageInfos64 (img_info_list[i].name, NULL, &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%08" PRIx64 " size 0x%08lx\n",
- img_info_list[i].name,
- img_info_list[i].base,
- img_info_list[i].size);
+ {
+ int tst;
+ ULONG64 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 ("%-*s base 0x%0*" PRIx64 " size 0x%08lx %c\n",
+ machine == IMAGE_FILE_MACHINE_I386 ? 45 : 37,
+ img_info_list[i].name,
+ machine == IMAGE_FILE_MACHINE_I386 ? 8 : 16,
+ img_info_list[i].base,
+ img_info_list[i].size,
+ img_info_list[i].flag.needs_rebasing ? '*' : ' ');
+ }
}
BOOL
-rebase (const char *pathname, ULONG64 *new_image_base)
+rebase (const char *pathname, ULONG64 *new_image_base, BOOL down_flag)
{
ULONG64 old_image_base, prev_new_image_base;
ULONG old_image_size, new_image_size;
@@ -201,22 +894,16 @@ rebase (const char *pathname, ULONG64 *n
stupid search algorithm (e.g, PATH, etc.). */
if (access (pathname, F_OK) == -1)
{
- fprintf (stderr, "%s: skipped because nonexistent\n", pathname);
+ if (!quiet)
+ fprintf (stderr, "%s: skipped because nonexistent\n", pathname);
return TRUE;
}
/* Skip if not writable. */
if (access (pathname, W_OK) == -1)
{
- fprintf (stderr, "%s: skipped because not writable\n", pathname);
- return TRUE;
- }
-
- /* Skip if not rebaseable. */
- if (!is_rebaseable (pathname))
- {
- if (verbose)
- fprintf (stderr, "%s: skipped because not rebaseable\n", pathname);
+ if (!quiet)
+ fprintf (stderr, "%s: skipped because not writable\n", pathname);
return TRUE;
}
@@ -312,18 +999,47 @@ retry:
return TRUE;
}
+static struct option long_options[] = {
+ {"32", no_argument, NULL, '4'},
+ {"64", no_argument, NULL, '8'},
+ {"base", required_argument, NULL, 'b'},
+ {"down", no_argument, NULL, 'd'},
+ {"help", no_argument, NULL, 'h'},
+ {"usage", no_argument, NULL, 'h'},
+ {"info", no_argument, NULL, 'i'},
+ {"offset", required_argument, NULL, 'o'},
+ {"quiet", no_argument, NULL, 'q'},
+ {"database", no_argument, NULL, 's'},
+ {"filelist", required_argument, NULL, 'T'},
+ {"usage", no_argument, NULL, 'h'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, no_argument, NULL, 0 }
+};
+
+static const char *short_options = "48b:dhioq:sT:vV";
+
void
parse_args (int argc, char *argv[])
{
- const char *anOptions = "b:dio:T:vV";
- int anOption = 0;
+ int opt = 0;
- while ((anOption = getopt (argc, argv, anOptions)) != -1)
+ while ((opt = getopt_long (argc, argv, short_options, long_options, NULL))
+ != -1)
{
- switch (anOption)
+ switch (opt)
{
+ case '4':
+ machine = IMAGE_FILE_MACHINE_I386;
+ db_file = IMG_INFO_FILE_I386;
+ break;
+ case '8':
+ machine = IMAGE_FILE_MACHINE_AMD64;
+ db_file = IMG_INFO_FILE_AMD64;
+ break;
case 'b':
image_base = string_to_ulonglong (optarg);
+ force_rebase_flag = TRUE;
break;
case 'd':
down_flag = TRUE;
@@ -333,6 +1049,15 @@ parse_args (int argc, char *argv[])
break;
case 'o':
offset = string_to_ulonglong (optarg);
+ force_rebase_flag = TRUE;
+ break;
+ case 'q':
+ quiet = 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;
@@ -340,6 +1065,10 @@ parse_args (int argc, char *argv[])
case 'v':
verbose = TRUE;
break;
+ case 'h':
+ help ();
+ exit (1);
+ break;
case 'V':
version ();
exit (1);
@@ -351,7 +1080,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 ();
@@ -373,9 +1102,56 @@ void
usage ()
{
fprintf (stderr,
- "usage: rebase -b BaseAddress [-Vdv] [-o Offset] "
- "[-T FileList | -] Files...\n"
- " rebase -i [-T FileList | -] Files...\n");
+"usage: %s [-b BaseAddress] [-o Offset] [-48dsvV] [-T FileList | -] Files...\n"
+" %s -i [-48s] [-T FileList | -] Files...\n"
+" %s --help or --usage for full help text\n",
+ progname, progname, progname);
+}
+
+void
+help ()
+{
+ printf ("\
+Usage: %s [OPTIONS] [FILE]...\n\
+Rebase PE files, usually DLLs, to a specified address or address range.\n\
+\n\
+ -4, --32 Only rebase 32 bit DLLs."
+#ifndef __x86_64__
+ " This is the default."
+#endif
+"\n\
+ -8, --64 Only rebase 64 bit DLLs."
+#ifdef __x86_64__
+ " This is the default."
+#endif
+"\n\
+ -b, --base=BASEADDRESS Specifies the base address at which to start rebasing.\n\
+ -s, --database Utilize the rebase database to find unused memory\n\
+ slots to rebase the files on the command line to.\n\
+ (Implies -d).\n\
+ If -b is given, too, the database gets recreated.\n\
+ -i, --info Rather then rebasing, just print the current base\n\
+ address and size of the files. With -s, use the\n\
+ database. The files are ordered by base address.\n\
+ A '*' at the end of the line is printed if a\n\
+ collisions with an adjacent file is detected.\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, --down 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\
+ With the -s option, this option is implicitly set.\n\
+ -o, --offset=OFFSET Specify an additional offset between adjacent DLLs\n\
+ when rebasing. Default is no offset.\n\
+ -T, --filelist=FILE Also rebase the files specified in FILE. The format\n\
+ of FILE is one DLL per line.\n\
+ -q, --quiet Be quiet about non-critical issues.\n\
+ -v, --verbose Print some debug output.\n\
+ -V, --version Print version info and exit.\n\
+ -h, --help, --usage 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 10 Jul 2011 14:58:58 -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
@@ -22,7 +22,7 @@ tp2=${tp1:-.}
PATH=$(cd $tp2 && pwd):@bindir@:/bin
ProgramName=${0##*/}
-ProgramOptions='b:o:s:T:v'
+ProgramOptions='48b:o:s:T:v'
DefaultBaseAddress=0x70000000
DefaultOffset=@DEFAULT_OFFSET_VALUE@
DefaultVerbose=
@@ -32,31 +32,43 @@ DefaultSuffixes='dll|so'
# Define functions
usage()
{
- echo "usage: $ProgramName [-b BaseAddress] [-o Offset] [-s DllSuffix] [-T FileList | -] [-v]"
+ echo "usage: ${ProgramName} [-b BaseAddress] [-o Offset] [-s DllSuffix] [-T FileList | -] [-4|-8] [-v]"
exit 1
}
cleanup()
{
- rm -f "$TmpFile"
- exit $ExitCode
+ rm -f "${TmpFile}"
+ exit ${ExitCode}
}
# Set traps
trap cleanup 1 2 15
# Set defaults
-BaseAddress=$DefaultBaseAddress
-Offset=$DefaultOffset
-Verbose=$DefaultVerbose
-FileList=$DefaultFileList
-Suffixes=$DefaultSuffixes
+BaseAddress=""
+Offset="${DefaultOffset}"
+Verbose="${DefaultVerbose}"
+FileList="${DefaultFileList}"
+Suffixes="${DefaultSuffixes}"
+db_file_i386="@sysconfdir@/rebase.db.i386"
+db_file_x86_64="@sysconfdir@/rebase.db.x86_64"
+case `uname -m` in
+ i[3456]86)
+ db_file="${db_file_i386}";
+ Mach="-4"
+ ;;
+ x86_64)
+ Mach="-8"
+ db_file="${db_file_x86_64}"
+ ;;
+esac
# Verify only ash or dash processes are running
grep -E -q -i -v '/d?ash(.exe)?$' /proc/[0-9]*/exename
-if [ $? -eq 0 -a -z "$RebaseDebug" ]
+if [ $? -eq 0 -a -z "${RebaseDebug}" ]
then
- echo "$ProgramName: only ash or dash processes are allowed during rebasing"
+ echo "${ProgramName}: only ash or dash processes are allowed during rebasing"
echo " Exit all Cygwin processes and stop all Cygwin services."
echo " Execute ash (or dash) from Start/Run... or a cmd or command window."
echo " Execute '/bin/rebaseall' from ash (or dash)."
@@ -64,24 +76,43 @@ then
fi
# Parse command line arguments
-while getopts $ProgramOptions Option "$@"
+while getopts "${ProgramOptions}" Option "$@"
do
- case $Option in
+ case "${Option}" in
+ 4)
+ db_file="${db_file_i386}";
+ Mach="-4"
+ ;;
+ 8)
+ Mach="-8"
+ db_file="${db_file_x86_64}"
+ ;;
b)
- BaseAddress=$OPTARG;;
+ BaseAddress="${OPTARG}";;
o)
- Offset=$OPTARG;;
+ Offset="${OPTARG}";;
s)
- Suffixes="$Suffixes|$OPTARG";;
+ Suffixes="${Suffixes}|${OPTARG}";;
T)
- FileList="$OPTARG";;
+ FileList="${OPTARG}";;
v)
- Verbose=-v;;
+ Verbose="-v";;
\?)
usage;;
esac
done
+# Check if rebase database already exists.
+database_exists="no"
+[ -f "${db_file}" ] && 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}}"
@@ -112,16 +143,20 @@ find /etc/setup -name '*.lst.gz' | xargs
grep -E "\.($Suffixes)\$" |
sed -e '/cygwin1\.dll$/d' -e '/cyglsa.*\.dll$/d' \
-e '/sys-root\/mingw/d' \
- -e 's/^/\//' -e '/d?ash\.exe$/d' -e '/rebase\.exe$/d' >"$TmpFile"
+ -e 's/^/\//' -e '/d?ash\.exe$/d' -e '/rebase\.exe$/d' >"${TmpFile}"
# Append user supplied file list, if any
-if [ -n "$FileList" ]
+if [ -n "${FileList}" ]
then
- cat "$FileList" >>"$TmpFile"
+ cat "${FileList}" >>"${TmpFile}"
fi
-# Rebase files
-rebase $Verbose -d -b $BaseAddress -o $Offset -T "$TmpFile"
+if [ -z "${BaseAddress}" ]
+then
+ ./rebase "${Verbose}" -s "${Mach}" -T "${TmpFile}"
+else
+ ./rebase "${Verbose}" -s "${Mach}" -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