]> code.delx.au - gnu-emacs/blobdiff - src/unexw32.c
(Version, mh-version): Update for release 8.0.
[gnu-emacs] / src / unexw32.c
index 743ce0086f6e14172e824b52561f809ff33637ae..6256062aa3f8e5527761a26a9c25cd522cc950dc 100644 (file)
@@ -1,5 +1,6 @@
 /* unexec for GNU Emacs on Windows NT.
-   Copyright (C) 1994 Free Software Foundation, Inc.
+   Copyright (C) 1994, 2002, 2003, 2004, 2005,
+                 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -15,15 +16,14 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.
 
    Geoff Voelker (voelker@cs.washington.edu)                         8-12-94
 */
 
 #include <config.h>
 
-#include <stdlib.h>    /* _fmode */
 #include <stdio.h>
 #include <fcntl.h>
 #include <time.h>
@@ -67,17 +67,17 @@ void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile);
 
 /* Cached info about the .data section in the executable.  */
 PIMAGE_SECTION_HEADER data_section;
-PUCHAR data_start = 0;
+PCHAR  data_start = 0;
 DWORD  data_size = 0;
 
 /* Cached info about the .bss section in the executable.  */
 PIMAGE_SECTION_HEADER bss_section;
-PUCHAR bss_start = 0;
+PCHAR  bss_start = 0;
 DWORD  bss_size = 0;
 DWORD  extra_bss_size = 0;
 /* bss data that is static might be discontiguous from non-static.  */
 PIMAGE_SECTION_HEADER bss_section_static;
-PUCHAR bss_start_static = 0;
+PCHAR  bss_start_static = 0;
 DWORD  bss_size_static = 0;
 DWORD  extra_bss_size_static = 0;
 
@@ -112,10 +112,6 @@ _start (void)
   /* Grab our malloc arena space now, before CRT starts up. */
   init_heap ();
 
-  /* The default behavior is to treat files as binary and patch up
-     text files appropriately, in accordance with the MSDOS code.  */
-  _fmode = O_BINARY;
-
   /* This prevents ctrl-c's in shells running while we're suspended from
      having us exit.  */
   SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE);
@@ -148,17 +144,17 @@ open_input_file (file_data *p_file, char *filename)
 
   file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
                     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
-  if (file == INVALID_HANDLE_VALUE) 
+  if (file == INVALID_HANDLE_VALUE)
     return FALSE;
 
   size = GetFileSize (file, &upper_size);
-  file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY, 
+  file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
                                    0, size, NULL);
-  if (!file_mapping) 
+  if (!file_mapping)
     return FALSE;
 
   file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
-  if (file_base == 0) 
+  if (file_base == 0)
     return FALSE;
 
   p_file->name = filename;
@@ -179,18 +175,18 @@ open_output_file (file_data *p_file, char *filename, unsigned long size)
 
   file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
                     CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
-  if (file == INVALID_HANDLE_VALUE) 
+  if (file == INVALID_HANDLE_VALUE)
     return FALSE;
 
-  file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE, 
+  file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
                                    0, size, NULL);
-  if (!file_mapping) 
+  if (!file_mapping)
     return FALSE;
-  
+
   file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
-  if (file_base == 0) 
+  if (file_base == 0)
     return FALSE;
-  
+
   p_file->name = filename;
   p_file->size = size;
   p_file->file = file;
@@ -284,7 +280,7 @@ offset_to_section (DWORD offset, IMAGE_NT_HEADERS * nt_header)
 /* Return offset to an object in dst, given offset in src.  We assume
    there is at least one section in both src and dst images, and that
    the some sections may have been added to dst (after sections in src).  */
-static DWORD
+DWORD
 relocate_offset (DWORD offset,
                 IMAGE_NT_HEADERS * src_nt_header,
                 IMAGE_NT_HEADERS * dst_nt_header)
@@ -330,39 +326,42 @@ relocate_offset (DWORD offset,
 /* Convert address in executing image to RVA.  */
 #define PTR_TO_RVA(ptr) ((DWORD)(ptr) - (DWORD) GetModuleHandle (NULL))
 
+#define RVA_TO_PTR(var,section,filedata) \
+         ((void *)(RVA_TO_OFFSET(var,section) + (filedata).file_base))
+
 #define PTR_TO_OFFSET(ptr, pfile_data) \
-          ((char *)(ptr) - (pfile_data)->file_base)
+          ((unsigned char *)(ptr) - (pfile_data)->file_base)
 
 #define OFFSET_TO_PTR(offset, pfile_data) \
           ((pfile_data)->file_base + (DWORD)(offset))
 
 
 /* Flip through the executable and cache the info necessary for dumping.  */
-static void
+void
 get_section_info (file_data *p_infile)
 {
   PIMAGE_DOS_HEADER dos_header;
   PIMAGE_NT_HEADERS nt_header;
   PIMAGE_SECTION_HEADER section;
   int overlap;
-  
+
   dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
-  if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) 
+  if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
     {
       printf ("Unknown EXE header in %s...bailing.\n", p_infile->name);
       exit (1);
     }
-  nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) + 
+  nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +
                                   dos_header->e_lfanew);
-  if (nt_header == NULL) 
+  if (nt_header == NULL)
     {
-      printf ("Failed to find IMAGE_NT_HEADER in %s...bailing.\n", 
+      printf ("Failed to find IMAGE_NT_HEADER in %s...bailing.\n",
             p_infile->name);
       exit (1);
     }
 
   /* Check the NT header signature ...  */
-  if (nt_header->Signature != IMAGE_NT_SIGNATURE) 
+  if (nt_header->Signature != IMAGE_NT_SIGNATURE)
     {
       printf ("Invalid IMAGE_NT_SIGNATURE 0x%x in %s...bailing.\n",
              nt_header->Signature, p_infile->name);
@@ -380,13 +379,31 @@ get_section_info (file_data *p_infile)
      area for the bss section, so we can make the new image the correct
      size.  */
 
-  data_start = my_begdata;
-  data_size = my_edata - my_begdata;
-  data_section = rva_to_section (PTR_TO_RVA (my_begdata), nt_header);
-  if (data_section != rva_to_section (PTR_TO_RVA (my_edata), nt_header))
+  /* We arrange for the Emacs initialized data to be in a separate
+     section if possible, because we cannot rely on my_begdata and
+     my_edata marking out the full extent of the initialized data, at
+     least on the Alpha where the linker freely reorders variables
+     across libraries.  If we can arrange for this, all we need to do is
+     find the start and size of the EMDATA section.  */
+  data_section = find_section ("EMDATA", nt_header);
+  if (data_section)
     {
-      printf ("Initialized data is not in a single section...bailing\n");
-      exit (1);
+      data_start = (char *) nt_header->OptionalHeader.ImageBase +
+       data_section->VirtualAddress;
+      data_size = data_section->Misc.VirtualSize;
+    }
+  else
+    {
+      /* Fallback on the old method if compiler doesn't support the
+         data_set #pragma (or its equivalent).  */
+      data_start = my_begdata;
+      data_size = my_edata - my_begdata;
+      data_section = rva_to_section (PTR_TO_RVA (my_begdata), nt_header);
+      if (data_section != rva_to_section (PTR_TO_RVA (my_edata), nt_header))
+       {
+         printf ("Initialized data is not in a single section...bailing\n");
+         exit (1);
+       }
     }
 
   /* As noted in lastfile.c, the Alpha (but not the Intel) MSVC linker
@@ -429,7 +446,11 @@ get_section_info (file_data *p_infile)
     - bss_section_static->SizeOfRawData;
 
   /* Combine the bss sections into one if they overlap.  */
+#ifdef _ALPHA_
+  overlap = 1;                 /* force all bss data to be dumped */
+#else
   overlap = 0;
+#endif
   if (bss_start < bss_start_static)
     {
       if (bss_start_static < bss_start + bss_size)
@@ -459,8 +480,8 @@ get_section_info (file_data *p_infile)
 
 /* The dump routines.  */
 
-static void
-copy_executable_and_dump_data (file_data *p_infile, 
+void
+copy_executable_and_dump_data (file_data *p_infile,
                               file_data *p_outfile)
 {
   unsigned char *dst, *dst_save;
@@ -471,27 +492,34 @@ copy_executable_and_dump_data (file_data *p_infile,
   PIMAGE_SECTION_HEADER dst_section;
   DWORD offset;
   int i;
+  int be_verbose = GetEnvironmentVariable ("DEBUG_DUMP", NULL, 0) > 0;
 
-#define COPY_CHUNK(message, src, size                                        \
+#define COPY_CHUNK(message, src, size, verbose)                                        \
   do {                                                                         \
     unsigned char *s = (void *)(src);                                          \
     unsigned long count = (size);                                              \
-    printf ("%s\n", (message));                                                        \
-    printf ("\t0x%08x Offset in input file.\n", s - p_infile->file_base);      \
-    printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base);  \
-    printf ("\t0x%08x Size in bytes.\n", count);                               \
+    if (verbose)                                                               \
+      {                                                                                \
+       printf ("%s\n", (message));                                             \
+       printf ("\t0x%08x Offset in input file.\n", s - p_infile->file_base);   \
+       printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
+       printf ("\t0x%08x Size in bytes.\n", count);                            \
+      }                                                                                \
     memcpy (dst, s, count);                                                    \
     dst += count;                                                              \
   } while (0)
 
-#define COPY_PROC_CHUNK(message, src, size)                                    \
+#define COPY_PROC_CHUNK(message, src, size, verbose)                           \
   do {                                                                         \
     unsigned char *s = (void *)(src);                                          \
     unsigned long count = (size);                                              \
-    printf ("%s\n", (message));                                                        \
-    printf ("\t0x%08x Address in process.\n", s);                              \
-    printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base);  \
-    printf ("\t0x%08x Size in bytes.\n", count);                               \
+    if (verbose)                                                               \
+      {                                                                                \
+       printf ("%s\n", (message));                                             \
+       printf ("\t0x%08x Address in process.\n", s);                           \
+       printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
+       printf ("\t0x%08x Size in bytes.\n", count);                            \
+      }                                                                                \
     memcpy (dst, s, count);                                                    \
     dst += count;                                                              \
   } while (0)
@@ -515,20 +543,21 @@ copy_executable_and_dump_data (file_data *p_infile,
      Note that dst is updated implicitly by each COPY_CHUNK.  */
 
   dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
-  nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) + 
+  nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +
                                   dos_header->e_lfanew);
   section = IMAGE_FIRST_SECTION (nt_header);
+
   dst = (unsigned char *) p_outfile->file_base;
 
   COPY_CHUNK ("Copying DOS header...", dos_header,
-             (DWORD) nt_header - (DWORD) dos_header);
+             (DWORD) nt_header - (DWORD) dos_header, be_verbose);
   dst_nt_header = (PIMAGE_NT_HEADERS) dst;
   COPY_CHUNK ("Copying NT header...", nt_header,
-             (DWORD) section - (DWORD) nt_header);
+             (DWORD) section - (DWORD) nt_header, be_verbose);
   dst_section = (PIMAGE_SECTION_HEADER) dst;
   COPY_CHUNK ("Copying section table...", section,
-             nt_header->FileHeader.NumberOfSections * sizeof (*section));
+             nt_header->FileHeader.NumberOfSections * sizeof (*section),
+             be_verbose);
 
   /* Align the first section's raw data area, and set the header size
      field accordingly.  */
@@ -538,7 +567,9 @@ copy_executable_and_dump_data (file_data *p_infile,
   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
     {
       char msg[100];
-      sprintf (msg, "Copying raw data for %s...", section->Name);
+      /* Windows section names are fixed 8-char strings, only
+        zero-terminated if the name is shorter than 8 characters.  */
+      sprintf (msg, "Copying raw data for %.8s...", section->Name);
 
       dst_save = dst;
 
@@ -551,7 +582,7 @@ copy_executable_and_dump_data (file_data *p_infile,
       /* Can always copy the original raw data.  */
       COPY_CHUNK
        (msg, OFFSET_TO_PTR (section->PointerToRawData, p_infile),
-        section->SizeOfRawData);
+        section->SizeOfRawData, be_verbose);
       /* Ensure alignment slop is zeroed.  */
       ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
 
@@ -560,7 +591,8 @@ copy_executable_and_dump_data (file_data *p_infile,
        {
          dst = dst_save
            + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (data_start), dst_section);
-         COPY_PROC_CHUNK ("Dumping initialized data...", data_start, data_size);
+         COPY_PROC_CHUNK ("Dumping initialized data...",
+                          data_start, data_size, be_verbose);
          dst = dst_save + dst_section->SizeOfRawData;
        }
       if (section == bss_section)
@@ -569,7 +601,8 @@ copy_executable_and_dump_data (file_data *p_infile,
              data size as necessary.  */
          dst = dst_save
            + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start), dst_section);
-         COPY_PROC_CHUNK ("Dumping bss data...", bss_start, bss_size);
+         COPY_PROC_CHUNK ("Dumping bss data...", bss_start,
+                          bss_size, be_verbose);
          ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
          dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
          /* Determine new size of raw data area.  */
@@ -584,7 +617,8 @@ copy_executable_and_dump_data (file_data *p_infile,
              section's raw data size as necessary.  */
          dst = dst_save
            + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start_static), dst_section);
-         COPY_PROC_CHUNK ("Dumping static bss data...", bss_start_static, bss_size_static);
+         COPY_PROC_CHUNK ("Dumping static bss data...", bss_start_static,
+                          bss_size_static, be_verbose);
          ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
          dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
          /* Determine new size of raw data area.  */
@@ -595,14 +629,15 @@ copy_executable_and_dump_data (file_data *p_infile,
        }
       if (section == heap_section)
        {
-         DWORD heap_start = get_heap_start ();
+         DWORD heap_start = (DWORD) get_heap_start ();
          DWORD heap_size = get_committed_heap_size ();
 
          /* Dump the used portion of the predump heap, adjusting the
              section's size to the appropriate size.  */
          dst = dst_save
            + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (heap_start), dst_section);
-         COPY_PROC_CHUNK ("Dumping heap...", heap_start, heap_size);
+         COPY_PROC_CHUNK ("Dumping heap...", heap_start, heap_size,
+                          be_verbose);
          ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
          dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
          /* Determine new size of raw data area.  */
@@ -637,7 +672,7 @@ copy_executable_and_dump_data (file_data *p_infile,
   COPY_CHUNK
     ("Copying remainder of executable...",
      OFFSET_TO_PTR (offset, p_infile),
-     p_infile->size - offset);
+     p_infile->size - offset, be_verbose);
 
   /* Final size for new image.  */
   p_outfile->size = DST_TO_OFFSET ();
@@ -697,18 +732,28 @@ unexec (char *new_name, char *old_name, void *start_data, void *start_bss,
   file_data in_file, out_file;
   char out_filename[MAX_PATH], in_filename[MAX_PATH];
   unsigned long size;
-  char *ptr;
-  
-  /* Make sure that the input and output filenames have the
-     ".exe" extension...patch them up if they don't.  */
-  strcpy (in_filename, old_name);
-  ptr = in_filename + strlen (in_filename) - 4;
-  if (strcmp (ptr, ".exe"))
-    strcat (in_filename, ".exe");
-
-  strcpy (out_filename, new_name);
-  ptr = out_filename + strlen (out_filename) - 4;
-  if (strcmp (ptr, ".exe"))
+  char *p;
+  char *q;
+
+  /* Ignore old_name, and get our actual location from the OS.  */
+  if (!GetModuleFileName (NULL, in_filename, MAX_PATH))
+    abort ();
+  dostounix_filename (in_filename);
+  strcpy (out_filename, in_filename);
+
+  /* Change the base of the output filename to match the requested name.  */
+  if ((p = strrchr (out_filename, '/')) == NULL)
+    abort ();
+  /* The filenames have already been expanded, and will be in Unix
+     format, so it is safe to expect an absolute name.  */
+  if ((q = strrchr (new_name, '/')) == NULL)
+    abort ();
+  strcpy (p, q);
+
+  /* Make sure that the output filename has the ".exe" extension...patch
+     it up if not.  */
+  p = out_filename + strlen (out_filename) - 4;
+  if (strcmp (p, ".exe"))
     strcat (out_filename, ".exe");
 
   printf ("Dumping from %s\n", in_filename);
@@ -720,7 +765,7 @@ unexec (char *new_name, char *old_name, void *start_data, void *start_bss,
   /* Open the undumped executable file.  */
   if (!open_input_file (&in_file, in_filename))
     {
-      printf ("Failed to open %s (%d)...bailing.\n", 
+      printf ("Failed to open %s (%d)...bailing.\n",
              in_filename, GetLastError ());
       exit (1);
     }
@@ -736,7 +781,7 @@ unexec (char *new_name, char *old_name, void *start_data, void *start_bss,
     extra_bss_size_static;
   if (!open_output_file (&out_file, out_filename, size))
     {
-      printf ("Failed to open %s (%d)...bailing.\n", 
+      printf ("Failed to open %s (%d)...bailing.\n",
              out_filename, GetLastError ());
       exit (1);
     }
@@ -780,3 +825,6 @@ unexec (char *new_name, char *old_name, void *start_data, void *start_bss,
 }
 
 /* eof */
+
+/* arch-tag: fe1d3d1c-ef88-4917-ab22-f12ab16b3254
+   (do not change this comment) */