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>
-extern BOOL ctrl_c_handler (unsigned long type);
+/* Include relevant definitions from IMAGEHLP.H, which can be found
+ in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
-#include "w32heap.h"
+PIMAGE_NT_HEADERS
+(__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
+ DWORD FileLength,
+ LPDWORD HeaderSum,
+ LPDWORD CheckSum);
-/* 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;
+extern BOOL ctrl_c_handler (unsigned long type);
+
+extern char my_begdata[];
+extern char my_edata[];
+extern char my_begbss[];
+extern char my_endbss[];
-/* 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;
/* 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);
{
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 ();
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. */
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);
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;
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);
}
/* File handling. */
-void
+int
open_input_file (file_data *p_file, char *filename)
{
HANDLE file;
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);
*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)
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. */
bss_start = ptr;
bss_size = get_section_size (section);
}
+#endif
+#if 0
if (!strcmp (section->Name, ".data"))
{
/* From lastfile.c */
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
bss_start = ptr + nt_header->OptionalHeader.ImageBase
+ data_section->VirtualAddress;
}
+#else
+ bss_start = my_begbss;
+ bss_size = my_endbss - bss_start;
+#endif
}