changeset 19703:9fa57c73882d

Include config.h and time.h. Declare extern data and functions. (file_data): Move definition from w32heap.c. (_start): Add debug hook for when profiling. Spoof executable name when using profilers. Invoke sbrk immediately when undumped. (unexec): Print error messages when input and output dump files cannot be opened. Reset header checksum. (open_input_file, open_output_file): Return status instead of aborting. (get_section_size): Handle different linkers. (find_section, rva_to_section): New functions. (get_section_info) [SEPARATE_BSS_SECTION]: Make code for using a separate .bss section conditional. Use my_begbss and my_endbss to determine .bss size by default. Look for Emacs data in EMDATA section.
author Geoff Voelker <voelker@cs.washington.edu>
date Wed, 03 Sep 1997 00:42:10 +0000
parents e59ec4e58fce
children 974a890c1d12
files src/unexw32.c
diffstat 1 files changed, 172 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/src/unexw32.c	Wed Sep 03 00:41:32 1997 +0000
+++ b/src/unexw32.c	Wed Sep 03 00:42:10 1997 +0000
@@ -21,27 +21,31 @@
    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>
 #include <windows.h>
 
+/* Include relevant definitions from IMAGEHLP.H, which can be found
+   in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
+
+PIMAGE_NT_HEADERS
+(__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
+				    DWORD FileLength,
+				    LPDWORD HeaderSum,
+				    LPDWORD CheckSum);
+
 extern BOOL ctrl_c_handler (unsigned long type);
 
-#include "w32heap.h"
+extern char my_begdata[];
+extern char my_edata[];
+extern char my_begbss[];
+extern char my_endbss[];
 
-/* A convenient type for keeping all the info about a mapped file together.  */
-typedef struct file_data {
-    char          *name;
-    unsigned long  size;
-    HANDLE         file;
-    HANDLE         file_mapping;
-    unsigned char *file_base;
-} file_data;
-
-/* Force zero initialized variables to be placed in the .data segment;
-   MSVC 5.0 otherwise places them in .bss, which breaks the dumping code.  */
-#pragma data_seg(".data")
+#include "w32heap.h"
 
 /* Basically, our "initialized" flag.  */
 BOOL need_to_recreate_heap = FALSE;
@@ -49,8 +53,8 @@
 /* So we can find our heap in the file to recreate it.  */
 unsigned long heap_index_in_executable = 0;
 
-void open_input_file (file_data *p_file, char *name);
-void open_output_file (file_data *p_file, char *name, unsigned long size);
+int open_input_file (file_data *p_file, char *name);
+int open_output_file (file_data *p_file, char *name, unsigned long size);
 void close_file_data (file_data *p_file);
 
 void get_section_info (file_data *p_file);
@@ -82,6 +86,13 @@
 {
   extern void mainCRTStartup (void);
 
+#if 0
+  /* Give us a way to debug problems with crashes on startup when
+     running under the MSVC profiler. */
+  if (GetEnvironmentVariable ("EMACS_DEBUG", NULL, 0) > 0)
+    DebugBreak ();
+#endif
+
   /* Cache system info, e.g., the NT page size.  */
   cache_system_info ();
 
@@ -99,9 +110,35 @@
 	  printf ("Failed to find path for executable.\n");
 	  exit (1);
 	}
+
+#if 1
+      /* To allow profiling, make sure executable_path names the .exe
+	 file, not the ._xe file created by the profiler which contains
+	 extra code that makes the stored exe offsets incorrect.  (This
+	 will not be necessary when unexec properly extends the .bss (or
+	 .data as appropriate) section to include the dumped bss data,
+	 and dumps the heap into a proper section of its own.)  */
+      {
+	char * p = strrchr (executable_path, '.');
+	if (p && p[1] == '_')
+	  p[1] = 'e';
+      }
+
+      /* Using HiProf profiler, exe name is different still. */
+      {
+	char * p = strrchr (executable_path, '\\');
+	strcpy (p, "\\emacs.exe");
+      }
+#endif
+
       recreate_heap (executable_path);
       need_to_recreate_heap = FALSE;
     }
+  else
+    {
+      /* Grab our malloc arena space now, before CRT starts up. */
+      sbrk (0);
+    }
 
   /* The default behavior is to treat files as binary and patch up
      text files appropriately, in accordance with the MSDOS code.  */
@@ -151,7 +188,12 @@
   round_heap (get_allocation_unit ());
 
   /* Open the undumped executable file.  */
-  open_input_file (&in_file, in_filename);
+  if (!open_input_file (&in_file, in_filename))
+    {
+      printf ("Failed to open %s (%d)...bailing.\n", 
+	      in_filename, GetLastError ());
+      exit (1);
+    }
 
   /* Get the interesting section info, like start and size of .bss...  */
   get_section_info (&in_file);
@@ -161,7 +203,12 @@
   heap_index_in_executable = (unsigned long)
     round_to_next ((unsigned char *) in_file.size, get_allocation_unit ());
   size = heap_index_in_executable + get_committed_heap_size () + bss_size;
-  open_output_file (&out_file, out_filename, size);
+  if (!open_output_file (&out_file, out_filename, size))
+    {
+      printf ("Failed to open %s (%d)...bailing.\n", 
+	      out_filename, GetLastError ());
+      exit (1);
+    }
 
   /* Set the flag (before dumping).  */
   need_to_recreate_heap = TRUE;
@@ -169,6 +216,35 @@
   copy_executable_and_dump_data_section (&in_file, &out_file);
   dump_bss_and_heap (&in_file, &out_file);
 
+  /* Patch up header fields; profiler is picky about this. */
+  {
+    PIMAGE_DOS_HEADER dos_header;
+    PIMAGE_NT_HEADERS nt_header;
+    HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
+    DWORD  headersum;
+    DWORD  checksum;
+
+    dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
+    nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
+
+    nt_header->OptionalHeader.CheckSum = 0;
+//    nt_header->FileHeader.TimeDateStamp = time (NULL);
+//    dos_header->e_cp = size / 512;
+//    nt_header->OptionalHeader.SizeOfImage = size;
+
+    pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
+    if (pfnCheckSumMappedFile)
+      {
+//	nt_header->FileHeader.TimeDateStamp = time (NULL);
+	pfnCheckSumMappedFile (out_file.file_base,
+			       out_file.size,
+			       &headersum,
+			       &checksum);
+	nt_header->OptionalHeader.CheckSum = checksum;
+      }
+    FreeLibrary (hImagehelp);
+  }
+
   close_file_data (&in_file);
   close_file_data (&out_file);
 }
@@ -177,7 +253,7 @@
 /* File handling.  */
 
 
-void 
+int
 open_input_file (file_data *p_file, char *filename)
 {
   HANDLE file;
@@ -188,83 +264,59 @@
   file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
 		     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
   if (file == INVALID_HANDLE_VALUE) 
-      {
-	printf ("Failed to open %s (%d)...bailing.\n", 
-	       filename, GetLastError ());
-	exit (1);
-      }
+    return FALSE;
 
   size = GetFileSize (file, &upper_size);
   file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY, 
 				    0, size, NULL);
   if (!file_mapping) 
-    {
-      printf ("Failed to create file mapping of %s (%d)...bailing.\n",
-	     filename, GetLastError ());
-      exit (1);
-    }
+    return FALSE;
 
   file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
   if (file_base == 0) 
-    {
-      printf ("Failed to map view of file of %s (%d)...bailing.\n",
-	     filename, GetLastError ());
-      exit (1);
-    }
+    return FALSE;
 
   p_file->name = filename;
   p_file->size = size;
   p_file->file = file;
   p_file->file_mapping = file_mapping;
   p_file->file_base = file_base;
+
+  return TRUE;
 }
 
-void 
+int
 open_output_file (file_data *p_file, char *filename, unsigned long size)
 {
   HANDLE file;
   HANDLE file_mapping;
   void  *file_base;
-  int    i;
 
   file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
 		     CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
   if (file == INVALID_HANDLE_VALUE) 
-    {
-      i = GetLastError ();
-      printf ("open_output_file: Failed to open %s (%d).\n", 
-	     filename, i);
-      exit (1);
-    }
-  
+    return FALSE;
+
   file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE, 
 				    0, size, NULL);
   if (!file_mapping) 
-    {
-      i = GetLastError ();
-      printf ("open_output_file: Failed to create file mapping of %s (%d).\n",
-	     filename, i);
-      exit (1);
-    }
+    return FALSE;
   
   file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
   if (file_base == 0) 
-    {
-      i = GetLastError ();
-      printf ("open_output_file: Failed to map view of file of %s (%d).\n",
-	     filename, i);
-      exit (1);
-    }
+    return FALSE;
   
   p_file->name = filename;
   p_file->size = size;
   p_file->file = file;
   p_file->file_mapping = file_mapping;
   p_file->file_base = file_base;
+
+  return TRUE;
 }
 
 /* Close the system structures associated with the given file.  */
-static void
+void
 close_file_data (file_data *p_file)
 {
     UnmapViewOfFile (p_file->file_base);
@@ -314,19 +366,54 @@
   *p_bss_size = (DWORD) len;
 }
 
-static unsigned long
+unsigned long
 get_section_size (PIMAGE_SECTION_HEADER p_section)
 {
-  /* The section size is in different locations in the different versions.  */
-  switch (get_w32_minor_version ()) 
+  /* The true section size, before rounding.  Some linkers swap the
+     meaning of these two values.  */
+  return min (p_section->SizeOfRawData,
+	      p_section->Misc.VirtualSize);
+}
+
+/* Return pointer to section header for named section. */
+IMAGE_SECTION_HEADER *
+find_section (char * name, IMAGE_NT_HEADERS * nt_header)
+{
+  PIMAGE_SECTION_HEADER section;
+  int i;
+
+  section = IMAGE_FIRST_SECTION (nt_header);
+
+  for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
     {
-    case 10:
-      return p_section->SizeOfRawData;
-    default:
-      return p_section->Misc.VirtualSize;
+      if (strcmp (section->Name, name) == 0)
+	return section;
+      section++;
     }
+  return NULL;
 }
 
+/* Return pointer to section header for section containing the given
+   relative virtual address. */
+IMAGE_SECTION_HEADER *
+rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
+{
+  PIMAGE_SECTION_HEADER section;
+  int i;
+
+  section = IMAGE_FIRST_SECTION (nt_header);
+
+  for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
+    {
+      if (rva >= section->VirtualAddress
+	  && rva < section->VirtualAddress + section->SizeOfRawData)
+	return section;
+      section++;
+    }
+  return NULL;
+}
+
+
 /* Flip through the executable and cache the info necessary for dumping.  */
 static void
 get_section_info (file_data *p_infile)
@@ -363,6 +450,7 @@
   section = (PIMAGE_SECTION_HEADER) IMAGE_FIRST_SECTION (nt_header);
   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) 
     {
+#ifdef SEPARATE_BSS_SECTION
       if (!strcmp (section->Name, ".bss")) 
 	{
 	  /* The .bss section.  */
@@ -371,6 +459,8 @@
 	  bss_start = ptr;
 	  bss_size = get_section_size (section);
 	}
+#endif
+#if 0
       if (!strcmp (section->Name, ".data")) 
 	{
 	  /* From lastfile.c  */
@@ -389,10 +479,25 @@
 	     than the one Emacs was dumped on).  */
 	  data_size = my_edata - data_start_va;
 	}
+#else
+      if (!strcmp (section->Name, "EMDATA")) 
+	{
+	  /* The Emacs initialized data section.  */
+	  data_section = section;
+	  ptr = (char *) nt_header->OptionalHeader.ImageBase +
+	    section->VirtualAddress;
+	  data_start_va = ptr;
+	  data_start_file = section->PointerToRawData;
+
+	  /* Write back the full section.  */
+	  data_size = get_section_size (section);
+	}
+#endif
       section++;
     }
 
-  if (!bss_start && !bss_size)
+#ifdef SEPARATE_BSS_SECTION
+  if (bss_start == UNINIT_PTR && bss_size == UNINIT_LONG)
     {
       /* Starting with MSVC 4.0, the .bss section has been eliminated
 	 and appended virtually to the end of the .data section.  Our
@@ -406,6 +511,10 @@
       bss_start = ptr + nt_header->OptionalHeader.ImageBase
 	+ data_section->VirtualAddress;
     }
+#else
+  bss_start = my_begbss;
+  bss_size = my_endbss - bss_start;
+#endif
 }