home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / e20313sr.zip / emacs / 20.3.1 / src / unexw32.c < prev    next >
C/C++ Source or Header  |  1999-07-31  |  23KB  |  734 lines

  1. /* unexec for GNU Emacs on Windows NT.
  2.    Copyright (C) 1994 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU Emacs.
  5.  
  6. GNU Emacs is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. GNU Emacs is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Emacs; see the file COPYING.  If not, write to
  18. the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19. Boston, MA 02111-1307, USA.
  20.  
  21.    Geoff Voelker (voelker@cs.washington.edu)                         8-12-94
  22. */
  23.  
  24. #include <config.h>
  25.  
  26. #include <stdlib.h>     /* _fmode */
  27. #include <stdio.h>
  28. #include <fcntl.h>
  29. #include <time.h>
  30. #include <windows.h>
  31.  
  32. /* Include relevant definitions from IMAGEHLP.H, which can be found
  33.    in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
  34.  
  35. PIMAGE_NT_HEADERS
  36. (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
  37.                     DWORD FileLength,
  38.                     LPDWORD HeaderSum,
  39.                     LPDWORD CheckSum);
  40.  
  41. extern BOOL ctrl_c_handler (unsigned long type);
  42.  
  43. extern char my_begdata[];
  44. extern char my_edata[];
  45. extern char my_begbss[];
  46. extern char my_endbss[];
  47. extern char *my_begbss_static;
  48. extern char *my_endbss_static;
  49.  
  50. #include "w32heap.h"
  51.  
  52. #undef min
  53. #undef max
  54. #define min(x, y) (((x) < (y)) ? (x) : (y))
  55. #define max(x, y) (((x) > (y)) ? (x) : (y))
  56.  
  57. /* Basically, our "initialized" flag.  */
  58. BOOL need_to_recreate_heap = FALSE;
  59.  
  60. /* So we can find our heap in the file to recreate it.  */
  61. unsigned long heap_index_in_executable = 0;
  62.  
  63. int open_input_file (file_data *p_file, char *name);
  64. int open_output_file (file_data *p_file, char *name, unsigned long size);
  65. void close_file_data (file_data *p_file);
  66.  
  67. void get_section_info (file_data *p_file);
  68. void copy_executable_and_dump_data_section (file_data *, file_data *);
  69. void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile);
  70.  
  71. /* Cached info about the .data section in the executable.  */
  72. PUCHAR data_start_va = 0;
  73. DWORD  data_start_file = 0;
  74. DWORD  data_size = 0;
  75.  
  76. /* Cached info about the .bss section in the executable.  */
  77. PUCHAR bss_start = 0;
  78. DWORD  bss_size = 0;
  79.  
  80. #ifdef HAVE_NTGUI
  81. HINSTANCE hinst = NULL;
  82. HINSTANCE hprevinst = NULL;
  83. LPSTR lpCmdLine = "";
  84. int nCmdShow = 0;
  85. #endif /* HAVE_NTGUI */
  86.  
  87. /* Startup code for running on NT.  When we are running as the dumped
  88.    version, we need to bootstrap our heap and .bss section into our
  89.    address space before we can actually hand off control to the startup
  90.    code supplied by NT (primarily because that code relies upon malloc ()).  */
  91. void
  92. _start (void)
  93. {
  94.   extern void mainCRTStartup (void);
  95.  
  96. #if 0
  97.   /* Give us a way to debug problems with crashes on startup when
  98.      running under the MSVC profiler. */
  99.   if (GetEnvironmentVariable ("EMACS_DEBUG", NULL, 0) > 0)
  100.     DebugBreak ();
  101. #endif
  102.  
  103.   /* Cache system info, e.g., the NT page size.  */
  104.   cache_system_info ();
  105.  
  106.   /* If we're a dumped version of emacs then we need to recreate
  107.      our heap and play tricks with our .bss section.  Do this before
  108.      start up.  (WARNING:  Do not put any code before this section
  109.      that relies upon malloc () and runs in the dumped version.  It
  110.      won't work.)  */
  111.   if (need_to_recreate_heap) 
  112.     {
  113.       char executable_path[MAX_PATH];
  114.  
  115.       if (GetModuleFileName (NULL, executable_path, MAX_PATH) == 0) 
  116.     {
  117.       printf ("Failed to find path for executable.\n");
  118.       exit (1);
  119.     }
  120.  
  121. #if 1
  122.       /* To allow profiling, make sure executable_path names the .exe
  123.      file, not the ._xe file created by the profiler which contains
  124.      extra code that makes the stored exe offsets incorrect.  (This
  125.      will not be necessary when unexec properly extends the .bss (or
  126.      .data as appropriate) section to include the dumped bss data,
  127.      and dumps the heap into a proper section of its own.)  */
  128.       {
  129.     char * p = strrchr (executable_path, '.');
  130.     if (p && p[1] == '_')
  131.       p[1] = 'e';
  132.       }
  133.  
  134.       /* Using HiProf profiler, exe name is different still. */
  135.       {
  136.     char * p = strrchr (executable_path, '\\');
  137.     strcpy (p, "\\emacs.exe");
  138.       }
  139. #endif
  140.  
  141.       recreate_heap (executable_path);
  142.       need_to_recreate_heap = FALSE;
  143.     }
  144.   else
  145.     {
  146.       /* Grab our malloc arena space now, before CRT starts up. */
  147.       sbrk (0);
  148.     }
  149.  
  150.   /* The default behavior is to treat files as binary and patch up
  151.      text files appropriately, in accordance with the MSDOS code.  */
  152.   _fmode = O_BINARY;
  153.  
  154.   /* This prevents ctrl-c's in shells running while we're suspended from
  155.      having us exit.  */
  156.   SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE);
  157.  
  158.   /* Invoke the NT CRT startup routine now that our housecleaning
  159.      is finished.  */
  160. #ifdef HAVE_NTGUI
  161.   /* determine WinMain args like crt0.c does */
  162.   hinst = GetModuleHandle(NULL);
  163.   lpCmdLine = GetCommandLine();
  164.   nCmdShow = SW_SHOWDEFAULT;
  165. #endif
  166.   mainCRTStartup ();
  167. }
  168.  
  169. /* Dump out .data and .bss sections into a new executable.  */
  170. void
  171. unexec (char *new_name, char *old_name, void *start_data, void *start_bss,
  172.     void *entry_address)
  173. {
  174.   file_data in_file, out_file;
  175.   char out_filename[MAX_PATH], in_filename[MAX_PATH];
  176.   unsigned long size;
  177.   char *ptr;
  178.   
  179.   /* Make sure that the input and output filenames have the
  180.      ".exe" extension...patch them up if they don't.  */
  181.   strcpy (in_filename, old_name);
  182.   ptr = in_filename + strlen (in_filename) - 4;
  183.   if (strcmp (ptr, ".exe"))
  184.     strcat (in_filename, ".exe");
  185.  
  186.   strcpy (out_filename, new_name);
  187.   ptr = out_filename + strlen (out_filename) - 4;
  188.   if (strcmp (ptr, ".exe"))
  189.     strcat (out_filename, ".exe");
  190.  
  191.   printf ("Dumping from %s\n", in_filename);
  192.   printf ("          to %s\n", out_filename);
  193.  
  194.   /* We need to round off our heap to NT's allocation unit (64KB).  */
  195.   round_heap (get_allocation_unit ());
  196.  
  197.   /* Open the undumped executable file.  */
  198.   if (!open_input_file (&in_file, in_filename))
  199.     {
  200.       printf ("Failed to open %s (%d)...bailing.\n", 
  201.           in_filename, GetLastError ());
  202.       exit (1);
  203.     }
  204.  
  205.   /* Get the interesting section info, like start and size of .bss...  */
  206.   get_section_info (&in_file);
  207.  
  208.   /* The size of the dumped executable is the size of the original
  209.      executable plus the size of the heap and the size of the .bss section.  */
  210.   heap_index_in_executable = (unsigned long)
  211.     round_to_next ((unsigned char *) in_file.size, get_allocation_unit ());
  212.   size = heap_index_in_executable + get_committed_heap_size () + bss_size;
  213.   if (!open_output_file (&out_file, out_filename, size))
  214.     {
  215.       printf ("Failed to open %s (%d)...bailing.\n", 
  216.           out_filename, GetLastError ());
  217.       exit (1);
  218.     }
  219.  
  220.   /* Set the flag (before dumping).  */
  221.   need_to_recreate_heap = TRUE;
  222.  
  223.   copy_executable_and_dump_data_section (&in_file, &out_file);
  224.   dump_bss_and_heap (&in_file, &out_file);
  225.  
  226.   /* Patch up header fields; profiler is picky about this. */
  227.   {
  228.     PIMAGE_DOS_HEADER dos_header;
  229.     PIMAGE_NT_HEADERS nt_header;
  230.     HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
  231.     DWORD  headersum;
  232.     DWORD  checksum;
  233.  
  234.     dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
  235.     nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
  236.  
  237.     nt_header->OptionalHeader.CheckSum = 0;
  238. //    nt_header->FileHeader.TimeDateStamp = time (NULL);
  239. //    dos_header->e_cp = size / 512;
  240. //    nt_header->OptionalHeader.SizeOfImage = size;
  241.  
  242.     pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
  243.     if (pfnCheckSumMappedFile)
  244.       {
  245. //    nt_header->FileHeader.TimeDateStamp = time (NULL);
  246.     pfnCheckSumMappedFile (out_file.file_base,
  247.                    out_file.size,
  248.                    &headersum,
  249.                    &checksum);
  250.     nt_header->OptionalHeader.CheckSum = checksum;
  251.       }
  252.     FreeLibrary (hImagehelp);
  253.   }
  254.  
  255.   close_file_data (&in_file);
  256.   close_file_data (&out_file);
  257. }
  258.  
  259.  
  260. /* File handling.  */
  261.  
  262.  
  263. int
  264. open_input_file (file_data *p_file, char *filename)
  265. {
  266.   HANDLE file;
  267.   HANDLE file_mapping;
  268.   void  *file_base;
  269.   unsigned long size, upper_size;
  270.  
  271.   file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
  272.              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  273.   if (file == INVALID_HANDLE_VALUE) 
  274.     return FALSE;
  275.  
  276.   size = GetFileSize (file, &upper_size);
  277.   file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY, 
  278.                     0, size, NULL);
  279.   if (!file_mapping) 
  280.     return FALSE;
  281.  
  282.   file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
  283.   if (file_base == 0) 
  284.     return FALSE;
  285.  
  286.   p_file->name = filename;
  287.   p_file->size = size;
  288.   p_file->file = file;
  289.   p_file->file_mapping = file_mapping;
  290.   p_file->file_base = file_base;
  291.  
  292.   return TRUE;
  293. }
  294.  
  295. int
  296. open_output_file (file_data *p_file, char *filename, unsigned long size)
  297. {
  298.   HANDLE file;
  299.   HANDLE file_mapping;
  300.   void  *file_base;
  301.  
  302.   file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
  303.              CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  304.   if (file == INVALID_HANDLE_VALUE) 
  305.     return FALSE;
  306.  
  307.   file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE, 
  308.                     0, size, NULL);
  309.   if (!file_mapping) 
  310.     return FALSE;
  311.   
  312.   file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
  313.   if (file_base == 0) 
  314.     return FALSE;
  315.   
  316.   p_file->name = filename;
  317.   p_file->size = size;
  318.   p_file->file = file;
  319.   p_file->file_mapping = file_mapping;
  320.   p_file->file_base = file_base;
  321.  
  322.   return TRUE;
  323. }
  324.  
  325. /* Close the system structures associated with the given file.  */
  326. void
  327. close_file_data (file_data *p_file)
  328. {
  329.     UnmapViewOfFile (p_file->file_base);
  330.     CloseHandle (p_file->file_mapping);
  331.     CloseHandle (p_file->file);
  332. }
  333.  
  334.  
  335. /* Routines to manipulate NT executable file sections.  */
  336.  
  337. #ifdef SEPARATE_BSS_SECTION
  338. static void
  339. get_bss_info_from_map_file (file_data *p_infile, PUCHAR *p_bss_start, 
  340.                 DWORD *p_bss_size)
  341. {
  342.   int n, start, len;
  343.   char map_filename[MAX_PATH];
  344.   char buffer[256];
  345.   FILE *map;
  346.  
  347.   /* Overwrite the .exe extension on the executable file name with
  348.      the .map extension.  */
  349.   strcpy (map_filename, p_infile->name);
  350.   n = strlen (map_filename) - 3;
  351.   strcpy (&map_filename[n], "map");
  352.  
  353.   map = fopen (map_filename, "r");
  354.   if (!map)
  355.     {
  356.       printf ("Failed to open map file %s, error %d...bailing out.\n",
  357.           map_filename, GetLastError ());
  358.       exit (-1);
  359.     }
  360.  
  361.   while (fgets (buffer, sizeof (buffer), map))
  362.     {
  363.       if (!(strstr (buffer, ".bss") && strstr (buffer, "DATA")))
  364.     continue;
  365.       n = sscanf (buffer, " %*d:%x %x", &start, &len);
  366.       if (n != 2)
  367.     {
  368.       printf ("Failed to scan the .bss section line:\n%s", buffer);
  369.       exit (-1);
  370.     }
  371.       break;
  372.     }
  373.   *p_bss_start = (PUCHAR) start;
  374.   *p_bss_size = (DWORD) len;
  375. }
  376. #endif
  377.  
  378. unsigned long
  379. get_section_size (PIMAGE_SECTION_HEADER p_section)
  380. {
  381.   /* The true section size, before rounding.  Some linkers swap the
  382.      meaning of these two values.  */
  383.   return min (p_section->SizeOfRawData,
  384.           p_section->Misc.VirtualSize);
  385. }
  386.  
  387. /* Return pointer to section header for named section. */
  388. IMAGE_SECTION_HEADER *
  389. find_section (char * name, IMAGE_NT_HEADERS * nt_header)
  390. {
  391.   PIMAGE_SECTION_HEADER section;
  392.   int i;
  393.  
  394.   section = IMAGE_FIRST_SECTION (nt_header);
  395.  
  396.   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
  397.     {
  398.       if (strcmp (section->Name, name) == 0)
  399.     return section;
  400.       section++;
  401.     }
  402.   return NULL;
  403. }
  404.  
  405. /* Return pointer to section header for section containing the given
  406.    relative virtual address. */
  407. IMAGE_SECTION_HEADER *
  408. rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
  409. {
  410.   PIMAGE_SECTION_HEADER section;
  411.   int i;
  412.  
  413.   section = IMAGE_FIRST_SECTION (nt_header);
  414.  
  415.   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
  416.     {
  417.       if (rva >= section->VirtualAddress
  418.       && rva < section->VirtualAddress + section->SizeOfRawData)
  419.     return section;
  420.       section++;
  421.     }
  422.   return NULL;
  423. }
  424.  
  425.  
  426. /* Flip through the executable and cache the info necessary for dumping.  */
  427. static void
  428. get_section_info (file_data *p_infile)
  429. {
  430.   PIMAGE_DOS_HEADER dos_header;
  431.   PIMAGE_NT_HEADERS nt_header;
  432.   PIMAGE_SECTION_HEADER section, data_section;
  433.   unsigned char *ptr;
  434.   int i;
  435.   
  436.   dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
  437.   if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) 
  438.     {
  439.       printf ("Unknown EXE header in %s...bailing.\n", p_infile->name);
  440.       exit (1);
  441.     }
  442.   nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) + 
  443.                    dos_header->e_lfanew);
  444.   if (nt_header == NULL) 
  445.     {
  446.       printf ("Failed to find IMAGE_NT_HEADER in %s...bailing.\n", 
  447.          p_infile->name);
  448.       exit (1);
  449.     }
  450.  
  451.   /* Check the NT header signature ...  */
  452.   if (nt_header->Signature != IMAGE_NT_SIGNATURE) 
  453.     {
  454.       printf ("Invalid IMAGE_NT_SIGNATURE 0x%x in %s...bailing.\n",
  455.           nt_header->Signature, p_infile->name);
  456.     }
  457.  
  458.   /* Flip through the sections for .data and .bss ...  */
  459.   section = (PIMAGE_SECTION_HEADER) IMAGE_FIRST_SECTION (nt_header);
  460.   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) 
  461.     {
  462. #ifdef SEPARATE_BSS_SECTION
  463.       if (!strcmp (section->Name, ".bss")) 
  464.     {
  465.       /* The .bss section.  */
  466.       ptr = (char *) nt_header->OptionalHeader.ImageBase +
  467.         section->VirtualAddress;
  468.       bss_start = ptr;
  469.       bss_size = get_section_size (section);
  470.     }
  471. #endif
  472. #if 0
  473.       if (!strcmp (section->Name, ".data")) 
  474.     {
  475.       /* From lastfile.c  */
  476.       extern char my_edata[];
  477.  
  478.       /* The .data section.  */
  479.       data_section = section;
  480.       ptr = (char *) nt_header->OptionalHeader.ImageBase +
  481.         section->VirtualAddress;
  482.       data_start_va = ptr;
  483.       data_start_file = section->PointerToRawData;
  484.  
  485.       /* We want to only write Emacs data back to the executable,
  486.          not any of the library data (if library data is included,
  487.          then a dumped Emacs won't run on system versions other
  488.          than the one Emacs was dumped on).  */
  489.       data_size = my_edata - data_start_va;
  490.     }
  491. #else
  492.       if (!strcmp (section->Name, "EMDATA")) 
  493.     {
  494.       /* The Emacs initialized data section.  */
  495.       data_section = section;
  496.       ptr = (char *) nt_header->OptionalHeader.ImageBase +
  497.         section->VirtualAddress;
  498.       data_start_va = ptr;
  499.       data_start_file = section->PointerToRawData;
  500.  
  501.       /* Write back the full section.  */
  502.       data_size = get_section_size (section);
  503.     }
  504. #endif
  505.       section++;
  506.     }
  507.  
  508. #ifdef SEPARATE_BSS_SECTION
  509.   if (bss_start == UNINIT_PTR && bss_size == UNINIT_LONG)
  510.     {
  511.       /* Starting with MSVC 4.0, the .bss section has been eliminated
  512.      and appended virtually to the end of the .data section.  Our
  513.      only hint about where the .bss section starts in the address
  514.      comes from the SizeOfRawData field in the .data section
  515.      header.  Unfortunately, this field is only approximate, as it
  516.      is a rounded number and is typically rounded just beyond the
  517.      start of the .bss section.  To find the start and size of the
  518.      .bss section exactly, we have to peek into the map file.  */
  519.       get_bss_info_from_map_file (p_infile, &ptr, &bss_size);
  520.       bss_start = ptr + nt_header->OptionalHeader.ImageBase
  521.     + data_section->VirtualAddress;
  522.     }
  523. #else
  524. /* As noted in lastfile.c, the Alpha (but not the Intel) MSVC linker
  525.    globally segregates all static and public bss data (ie. across all
  526.    linked modules, not just per module), so we must take both static and
  527.    public bss areas into account to determine the true extent of the bss
  528.    area used by Emacs.
  529.  
  530.    To be strictly correct, we should dump the static and public bss
  531.    areas used by Emacs separately if non-overlapping (since otherwise we
  532.    are dumping bss data belonging to system libraries, eg. the static
  533.    bss system data on the Alpha).  However, in practice this doesn't
  534.    seem to matter, since presumably the system libraries always
  535.    reinitialize their bss variables.  */
  536.   bss_start = min (my_begbss, my_begbss_static);
  537.   bss_size = max (my_endbss, my_endbss_static) - bss_start;
  538. #endif
  539. }
  540.  
  541.  
  542. /* The dump routines.  */
  543.  
  544. static void
  545. copy_executable_and_dump_data_section (file_data *p_infile, 
  546.                        file_data *p_outfile)
  547. {
  548.   unsigned char *data_file, *data_va;
  549.   unsigned long size, index;
  550.   
  551.   /* Get a pointer to where the raw data should go in the executable file.  */
  552.   data_file = (char *) p_outfile->file_base + data_start_file;
  553.  
  554.   /* Get a pointer to the raw data in our address space.  */
  555.   data_va = data_start_va;
  556.     
  557.   size = (DWORD) data_file - (DWORD) p_outfile->file_base;
  558.   printf ("Copying executable up to data section...\n");
  559.   printf ("\t0x%08x Offset in input file.\n", 0);
  560.   printf ("\t0x%08x Offset in output file.\n", 0);
  561.   printf ("\t0x%08x Size in bytes.\n", size);
  562.   memcpy (p_outfile->file_base, p_infile->file_base, size);
  563.   
  564.   size = data_size;
  565.   printf ("Dumping .data section...\n");
  566.   printf ("\t0x%08x Address in process.\n", data_va);
  567.   printf ("\t0x%08x Offset in output file.\n", 
  568.       data_file - p_outfile->file_base);
  569.   printf ("\t0x%08x Size in bytes.\n", size);
  570.   memcpy (data_file, data_va, size);
  571.   
  572.   index = (DWORD) data_file + size - (DWORD) p_outfile->file_base;
  573.   size = p_infile->size - index;
  574.   printf ("Copying rest of executable...\n");
  575.   printf ("\t0x%08x Offset in input file.\n", index);
  576.   printf ("\t0x%08x Offset in output file.\n", index);
  577.   printf ("\t0x%08x Size in bytes.\n", size);
  578.   memcpy ((char *) p_outfile->file_base + index, 
  579.       (char *) p_infile->file_base + index, size);
  580. }
  581.  
  582. static void
  583. dump_bss_and_heap (file_data *p_infile, file_data *p_outfile)
  584. {
  585.     unsigned char *heap_data, *bss_data;
  586.     unsigned long size, index;
  587.  
  588.     printf ("Dumping heap into executable...\n");
  589.  
  590.     index = heap_index_in_executable;
  591.     size = get_committed_heap_size ();
  592.     heap_data = get_heap_start ();
  593.  
  594.     printf ("\t0x%08x Heap start in process.\n", heap_data);
  595.     printf ("\t0x%08x Heap offset in executable.\n", index);
  596.     printf ("\t0x%08x Heap size in bytes.\n", size);
  597.  
  598.     memcpy ((PUCHAR) p_outfile->file_base + index, heap_data, size);
  599.  
  600.     printf ("Dumping .bss into executable...\n");
  601.     
  602.     index += size;
  603.     size = bss_size;
  604.     bss_data = bss_start;
  605.     
  606.     printf ("\t0x%08x BSS start in process.\n", bss_data);
  607.     printf ("\t0x%08x BSS offset in executable.\n", index);
  608.     printf ("\t0x%08x BSS size in bytes.\n", size);
  609.     memcpy ((char *) p_outfile->file_base + index, bss_data, size);
  610. }
  611.  
  612.  
  613. /* Reload and remap routines.  */
  614.  
  615. void
  616. w32_fatal_reload_error (char *step)
  617. {
  618.   int error = GetLastError ();
  619.   char *buffer = alloca (4096);
  620.  
  621.   sprintf (buffer, 
  622.        "Emacs failed to load its dumped heap back into its address space.\n"
  623.        "The error occurred during the following step:\n\n"
  624.        "%s\n\n"
  625.        "GetLastError = %d\n\n"
  626.        "Heap start:  0x%08x\n"
  627.        "Heap commit:  0x%08x\n"
  628.        "Heap end:  0x%08x\n\n"
  629.        "This error typically happens when the system loads a DLL into\n"
  630.        "the middle of Emacs' address space, preventing Emacs from\n"
  631.        "loading its heap there.  If this happens only occasionally, then\n"
  632.        "you can probably ignore it.  But if it happens so often that\n"
  633.        "you cannot get Emacs to start reliably, and you think that Emacs\n"
  634.        "is installed correctly, then you have a couple of options:\n\n"
  635.        "Emacs correctly, then you have two options:\n\n"
  636.        "1) You can dump Emacs yourself.  By doing this, you ensure that\n"
  637.        "Emacs' heap fits around the DLLs in your system.  To dump Emacs,\n"
  638.        "download the emacs-(version)-undump-(arch) distribution file\n"
  639.        "from the site where you downloaded the executable distribution.\n\n"
  640.        "2) You can build Emacs from source.  This is just another way\n"
  641.        "to dump Emacs on your system.",
  642.        step, 
  643.        error,
  644.        get_heap_start (), 
  645.        get_heap_start () + get_committed_heap_size (),
  646.        get_heap_end ());
  647.  
  648.   MessageBox (NULL,
  649.           buffer,
  650.           "Emacs Abort Dialog",
  651.           MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
  652.  
  653.   exit (-1);
  654. }
  655.  
  656. /* Load the dumped .bss section into the .bss area of our address space.  */
  657. void
  658. read_in_bss (char *filename)
  659. {
  660.   HANDLE file;
  661.   unsigned long size, index, n_read, total_read;
  662.   char   buffer[512], *bss;
  663.   int    i;
  664.  
  665.   file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
  666.              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  667.   if (file == INVALID_HANDLE_VALUE) 
  668.     w32_fatal_reload_error ("Opening Emacs executable file for .bss.");
  669.  
  670.   /* Seek to where the .bss section is tucked away after the heap...  */
  671.   index = heap_index_in_executable + get_committed_heap_size ();
  672.   if (SetFilePointer (file, index, NULL, FILE_BEGIN) == 0xFFFFFFFF) 
  673.     w32_fatal_reload_error ("Seeking to the saved .bss section.");
  674.   
  675.   /* Ok, read in the saved .bss section and initialize all 
  676.      uninitialized variables.  */
  677.   if (!ReadFile (file, bss_start, bss_size, &n_read, NULL))
  678.     w32_fatal_reload_error ("Reading the saved .bss section.");
  679.  
  680.   CloseHandle (file);
  681. }
  682.  
  683. /* Map the heap dumped into the executable file into our address space.  */
  684. void 
  685. map_in_heap (char *filename)
  686. {
  687.   HANDLE file;
  688.   HANDLE file_mapping;
  689.   void  *file_base;
  690.   unsigned long size, upper_size, n_read;
  691.   int    i;
  692.  
  693.   file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
  694.              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  695.   if (file == INVALID_HANDLE_VALUE) 
  696.     w32_fatal_reload_error ("Opening Emacs executable file for heap.");
  697.   
  698.   size = GetFileSize (file, &upper_size);
  699.   file_mapping = CreateFileMapping (file, NULL, PAGE_WRITECOPY, 
  700.                     0, size, NULL);
  701.   if (!file_mapping) 
  702.     w32_fatal_reload_error ("Creating file mapping to heap in executable.");
  703.     
  704.   size = get_committed_heap_size ();
  705.   file_base = MapViewOfFileEx (file_mapping, FILE_MAP_COPY, 0, 
  706.                    heap_index_in_executable, size,
  707.                    get_heap_start ());
  708.   if (file_base != 0) 
  709.     {
  710.       return;
  711.     }
  712.  
  713.   /* If we don't succeed with the mapping, then copy from the 
  714.      data into the heap.  */
  715.  
  716.   CloseHandle (file_mapping);
  717.  
  718.   if (VirtualAlloc (get_heap_start (), get_committed_heap_size (),
  719.             MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE) == NULL)
  720.     w32_fatal_reload_error ("Allocating heap address space.");
  721.  
  722.   /* Seek to the location of the heap data in the executable.  */
  723.   i = heap_index_in_executable;
  724.   if (SetFilePointer (file, i, NULL, FILE_BEGIN) == 0xFFFFFFFF)
  725.     w32_fatal_reload_error ("Seeking to saved heap in executable file.");
  726.  
  727.   /* Read in the data.  */
  728.   if (!ReadFile (file, get_heap_start (), 
  729.          get_committed_heap_size (), &n_read, NULL))
  730.     w32_fatal_reload_error ("Reading saved heap from executable file.");
  731.  
  732.   CloseHandle (file);
  733. }
  734.