Mercurial > emacs
changeset 12245:e8a6dfd8d5d2
Initial revision
author | Karl Heuer <kwzh@gnu.org> |
---|---|
date | Thu, 15 Jun 1995 20:45:57 +0000 |
parents | ac7375e60931 |
children | 4de2d34c04d3 |
files | src/unexw32.c |
diffstat | 1 files changed, 483 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/unexw32.c Thu Jun 15 20:45:57 1995 +0000 @@ -0,0 +1,483 @@ +/* + unexec for GNU Emacs on Windows NT. + + Copyright (C) 1994 Free Software Foundation, Inc. + + This file is part of GNU Emacs. + + GNU Emacs is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any later + version. + + GNU Emacs is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the 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, 675 Mass Ave, Cambridge, MA 02139, USA. + + Geoff Voelker (voelker@cs.washington.edu) 8-12-94 +*/ + +#include <stdlib.h> /* _fmode */ +#include <stdio.h> +#include <fcntl.h> +#include <windows.h> + +extern BOOL ctrl_c_handler (unsigned long type); + +#include "ntheap.h" + +/* 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; + +/* 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); +void close_file_data (file_data *p_file); + +void get_section_info (file_data *p_file); +void copy_executable_and_dump_data_section (file_data *, file_data *); +void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile); + +/* Cached info about the .data section in the executable. */ +PUCHAR data_start_va = 0; +DWORD data_start_file = 0; +DWORD data_size = 0; + +/* Cached info about the .bss section in the executable. */ +PUCHAR bss_start = 0; +DWORD bss_size = 0; + +/* Startup code for running on NT. When we are running as the dumped + version, we need to bootstrap our heap and .bss section into our + address space before we can actually hand off control to the startup + code supplied by NT (primarily because that code relies upon malloc ()). */ +void +_start (void) +{ + extern void mainCRTStartup (void); + + /* Cache system info, e.g., the NT page size. */ + cache_system_info (); + + /* If we're a dumped version of emacs then we need to recreate + our heap and play tricks with our .bss section. Do this before + start up. (WARNING: Do not put any code before this section + that relies upon malloc () and runs in the dumped version. It + won't work.) */ + if (need_to_recreate_heap) + { + char executable_path[MAX_PATH]; + + if (GetModuleFileName (NULL, executable_path, MAX_PATH) == 0) + { + printf ("Failed to find path for executable.\n"); + exit (1); + } + recreate_heap (executable_path); + need_to_recreate_heap = FALSE; + } + + /* 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); + + /* Invoke the NT CRT startup routine now that our housecleaning + is finished. */ + mainCRTStartup (); +} + +/* Dump out .data and .bss sections into a new exectubale. */ +void +unexec (char *new_name, char *old_name, void *start_data, void *start_bss, + void *entry_address) +{ + 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")) + strcat (out_filename, ".exe"); + + printf ("Dumping from %s\n", in_filename); + printf (" to %s\n", out_filename); + + /* We need to round off our heap to NT's allocation unit (64KB). */ + round_heap (get_allocation_unit ()); + + /* Open the undumped executable file. */ + open_input_file (&in_file, in_filename); + + /* Get the interesting section info, like start and size of .bss... */ + get_section_info (&in_file); + + /* The size of the dumped executable is the size of the original + executable plus the size of the heap and the size of the .bss section. */ + heap_index_in_executable = round_to_next (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); + + /* 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); + + close_file_data (&in_file); + close_file_data (&out_file); +} + + +/* File handling. */ + + +void +open_input_file (file_data *p_file, char *filename) +{ + HANDLE file; + HANDLE file_mapping; + void *file_base; + unsigned long size, upper_size; + + 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); + } + + 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); + } + + 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); + } + + p_file->name = filename; + p_file->size = size; + p_file->file = file; + p_file->file_mapping = file_mapping; + p_file->file_base = file_base; +} + +void +open_output_file (file_data *p_file, char *filename, unsigned long size) +{ + HANDLE file; + HANDLE file_mapping; + void *file_base; + + file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (file == INVALID_HANDLE_VALUE) + { + printf ("open_output_file: Failed to open %s (%d).\n", + filename, GetLastError ()); + exit (1); + } + + file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE, + 0, size, NULL); + if (!file_mapping) + { + printf ("open_output_file: Failed to create file mapping of %s (%d).\n", + filename, GetLastError ()); + exit (1); + } + + file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size); + if (file_base == 0) + { + printf ("open_output_file: Failed to map view of file of %s (%d).\n", + filename, GetLastError ()); + exit (1); + } + + p_file->name = filename; + p_file->size = size; + p_file->file = file; + p_file->file_mapping = file_mapping; + p_file->file_base = file_base; +} + +/* Close the system structures associated with the given file. */ +static void +close_file_data (file_data *p_file) +{ + UnmapViewOfFile (p_file->file_base); + CloseHandle (p_file->file_mapping); + CloseHandle (p_file->file); +} + + +/* Routines to manipulate NT executable file sections. */ + + +static unsigned long +get_section_size (PIMAGE_SECTION_HEADER p_section) +{ + /* The section size is in different locations in the different versions. */ + switch (get_nt_minor_version ()) + { + case 10: + return p_section->SizeOfRawData; + default: + return p_section->Misc.VirtualSize; + } +} + +/* Flip through the executable and cache the info necessary for dumping. */ +static void +get_section_info (file_data *p_infile) +{ + PIMAGE_DOS_HEADER dos_header; + PIMAGE_NT_HEADERS nt_header; + PIMAGE_SECTION_HEADER section; + unsigned char *ptr; + int i; + + dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base; + 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) + + dos_header->e_lfanew); + if (nt_header == NULL) + { + 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) + { + printf ("Invalid IMAGE_NT_SIGNATURE 0x%x in %s...bailing.\n", + nt_header->Signature, p_infile->name); + } + + /* Flip through the sections for .data and .bss ... */ + section = (PIMAGE_SECTION_HEADER) IMAGE_FIRST_SECTION (nt_header); + for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) + { + if (!strcmp (section->Name, ".bss")) + { + /* The .bss section. */ + ptr = (char *) nt_header->OptionalHeader.ImageBase + + section->VirtualAddress; + bss_start = ptr; + bss_size = get_section_size (section); + } + if (!strcmp (section->Name, ".data")) + { + /* The .data section. */ + ptr = (char *) nt_header->OptionalHeader.ImageBase + + section->VirtualAddress; + data_start_va = ptr; + data_start_file = section->PointerToRawData; + data_size = get_section_size (section); + } + section++; + } +} + + +/* The dump routines. */ + +static void +copy_executable_and_dump_data_section (file_data *p_infile, + file_data *p_outfile) +{ + unsigned char *data_file, *data_va; + unsigned long size, index; + + /* Get a pointer to where the raw data should go in the executable file. */ + data_file = (char *) p_outfile->file_base + data_start_file; + + /* Get a pointer to the raw data in our address space. */ + data_va = data_start_va; + + size = (DWORD) data_file - (DWORD) p_outfile->file_base; + printf ("Copying executable up to data section...\n"); + printf ("\t0x%08x Offset in input file.\n", 0); + printf ("\t0x%08x Offset in output file.\n", 0); + printf ("\t0x%08x Size in bytes.\n", size); + memcpy (p_outfile->file_base, p_infile->file_base, size); + + size = data_size; + printf ("Dumping .data section...\n"); + printf ("\t0x%08x Address in process.\n", data_va); + printf ("\t0x%08x Offset in output file.\n", + data_file - p_outfile->file_base); + printf ("\t0x%08x Size in bytes.\n", size); + memcpy (data_file, data_va, size); + + index = (DWORD) data_file + size - (DWORD) p_outfile->file_base; + size = p_infile->size - index; + printf ("Copying rest of executable...\n"); + printf ("\t0x%08x Offset in input file.\n", index); + printf ("\t0x%08x Offset in output file.\n", index); + printf ("\t0x%08x Size in bytes.\n", size); + memcpy ((char *) p_outfile->file_base + index, + (char *) p_infile->file_base + index, size); +} + +static void +dump_bss_and_heap (file_data *p_infile, file_data *p_outfile) +{ + unsigned char *heap_data, *bss_data; + unsigned long size, index; + + printf ("Dumping heap into executable...\n"); + + index = heap_index_in_executable; + size = get_committed_heap_size (); + heap_data = get_heap_start (); + + printf ("\t0x%08x Heap start in process.\n", heap_data); + printf ("\t0x%08x Heap offset in executable.\n", index); + printf ("\t0x%08x Heap size in bytes.\n", size); + + memcpy ((PUCHAR) p_outfile->file_base + index, heap_data, size); + + printf ("Dumping .bss into executable...\n"); + + index += size; + size = bss_size; + bss_data = bss_start; + + printf ("\t0x%08x BSS start in process.\n", bss_data); + printf ("\t0x%08x BSS offset in executable.\n", index); + printf ("\t0x%08x BSS size in bytes.\n", size); + memcpy ((char *) p_outfile->file_base + index, bss_data, size); +} + + +/* Reload and remap routines. */ + + +/* Load the dumped .bss section into the .bss area of our address space. */ +void +read_in_bss (char *filename) +{ + HANDLE file; + unsigned long size, index, n_read, total_read; + char buffer[512], *bss; + int i; + + file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (file == INVALID_HANDLE_VALUE) + { + i = GetLastError (); + exit (1); + } + + /* Seek to where the .bss section is tucked away after the heap... */ + index = heap_index_in_executable + get_committed_heap_size (); + if (SetFilePointer (file, index, NULL, FILE_BEGIN) == 0xFFFFFFFF) + { + i = GetLastError (); + exit (1); + } + + + /* Ok, read in the saved .bss section and initialize all + uninitialized variables. */ + total_read = 0; + size = bss_size; + bss = bss_start; + while (ReadFile (file, buffer, 512, &n_read, NULL)) + { + if (n_read == 0) + break; + memcpy (bss, buffer, n_read); + bss += n_read; + total_read += n_read; + } + + CloseHandle (file); +} + +/* Map the heap dumped into the executable file into our address space. */ +void +map_in_heap (char *filename) +{ + HANDLE file; + HANDLE file_mapping; + void *file_base; + unsigned long size, upper_size; + int i; + + file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (file == INVALID_HANDLE_VALUE) + { + i = GetLastError (); + exit (1); + } + + size = GetFileSize (file, &upper_size); + file_mapping = CreateFileMapping (file, NULL, PAGE_WRITECOPY, + 0, size, NULL); + if (!file_mapping) + { + i = GetLastError (); + exit (1); + } + + size = get_committed_heap_size (); + file_base = MapViewOfFileEx (file_mapping, FILE_MAP_COPY, 0, + heap_index_in_executable, size, + get_heap_start ()); + if (file_base == 0) + { + i = GetLastError (); + exit (1); + } +}