diff options
| author | Karl Heuer | 1995-06-15 20:45:57 +0000 |
|---|---|---|
| committer | Karl Heuer | 1995-06-15 20:45:57 +0000 |
| commit | 2147fb50c482582d33be0bb30dbc8a4b62b2ecff (patch) | |
| tree | f7b60166d4500ac0d3cea22c0d8dbc457588c8a1 /src | |
| parent | 7c938215cd28ae6b7c95d02c5e29839c9be68925 (diff) | |
| download | emacs-2147fb50c482582d33be0bb30dbc8a4b62b2ecff.tar.gz emacs-2147fb50c482582d33be0bb30dbc8a4b62b2ecff.zip | |
Initial revision
Diffstat (limited to 'src')
| -rw-r--r-- | src/unexw32.c | 483 |
1 files changed, 483 insertions, 0 deletions
diff --git a/src/unexw32.c b/src/unexw32.c new file mode 100644 index 00000000000..a29393aef74 --- /dev/null +++ b/src/unexw32.c | |||
| @@ -0,0 +1,483 @@ | |||
| 1 | /* | ||
| 2 | unexec for GNU Emacs on Windows NT. | ||
| 3 | |||
| 4 | Copyright (C) 1994 Free Software Foundation, Inc. | ||
| 5 | |||
| 6 | This file is part of GNU Emacs. | ||
| 7 | |||
| 8 | GNU Emacs is free software; you can redistribute it and/or modify it | ||
| 9 | under the terms of the GNU General Public License as published by the | ||
| 10 | Free Software Foundation; either version 2, or (at your option) any later | ||
| 11 | version. | ||
| 12 | |||
| 13 | GNU Emacs is distributed in the hope that it will be useful, but WITHOUT | ||
| 14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 16 | more details. | ||
| 17 | |||
| 18 | You should have received a copy of the GNU General Public License along | ||
| 19 | with GNU Emacs; see the file COPYING. If not, write to the Free Software | ||
| 20 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 21 | |||
| 22 | Geoff Voelker (voelker@cs.washington.edu) 8-12-94 | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <stdlib.h> /* _fmode */ | ||
| 26 | #include <stdio.h> | ||
| 27 | #include <fcntl.h> | ||
| 28 | #include <windows.h> | ||
| 29 | |||
| 30 | extern BOOL ctrl_c_handler (unsigned long type); | ||
| 31 | |||
| 32 | #include "ntheap.h" | ||
| 33 | |||
| 34 | /* A convenient type for keeping all the info about a mapped file together. */ | ||
| 35 | typedef struct file_data { | ||
| 36 | char *name; | ||
| 37 | unsigned long size; | ||
| 38 | HANDLE file; | ||
| 39 | HANDLE file_mapping; | ||
| 40 | unsigned char *file_base; | ||
| 41 | } file_data; | ||
| 42 | |||
| 43 | /* Basically, our "initialized" flag. */ | ||
| 44 | BOOL need_to_recreate_heap = FALSE; | ||
| 45 | |||
| 46 | /* So we can find our heap in the file to recreate it. */ | ||
| 47 | unsigned long heap_index_in_executable = 0; | ||
| 48 | |||
| 49 | void open_input_file (file_data *p_file, char *name); | ||
| 50 | void open_output_file (file_data *p_file, char *name, unsigned long size); | ||
| 51 | void close_file_data (file_data *p_file); | ||
| 52 | |||
| 53 | void get_section_info (file_data *p_file); | ||
| 54 | void copy_executable_and_dump_data_section (file_data *, file_data *); | ||
| 55 | void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile); | ||
| 56 | |||
| 57 | /* Cached info about the .data section in the executable. */ | ||
| 58 | PUCHAR data_start_va = 0; | ||
| 59 | DWORD data_start_file = 0; | ||
| 60 | DWORD data_size = 0; | ||
| 61 | |||
| 62 | /* Cached info about the .bss section in the executable. */ | ||
| 63 | PUCHAR bss_start = 0; | ||
| 64 | DWORD bss_size = 0; | ||
| 65 | |||
| 66 | /* Startup code for running on NT. When we are running as the dumped | ||
| 67 | version, we need to bootstrap our heap and .bss section into our | ||
| 68 | address space before we can actually hand off control to the startup | ||
| 69 | code supplied by NT (primarily because that code relies upon malloc ()). */ | ||
| 70 | void | ||
| 71 | _start (void) | ||
| 72 | { | ||
| 73 | extern void mainCRTStartup (void); | ||
| 74 | |||
| 75 | /* Cache system info, e.g., the NT page size. */ | ||
| 76 | cache_system_info (); | ||
| 77 | |||
| 78 | /* If we're a dumped version of emacs then we need to recreate | ||
| 79 | our heap and play tricks with our .bss section. Do this before | ||
| 80 | start up. (WARNING: Do not put any code before this section | ||
| 81 | that relies upon malloc () and runs in the dumped version. It | ||
| 82 | won't work.) */ | ||
| 83 | if (need_to_recreate_heap) | ||
| 84 | { | ||
| 85 | char executable_path[MAX_PATH]; | ||
| 86 | |||
| 87 | if (GetModuleFileName (NULL, executable_path, MAX_PATH) == 0) | ||
| 88 | { | ||
| 89 | printf ("Failed to find path for executable.\n"); | ||
| 90 | exit (1); | ||
| 91 | } | ||
| 92 | recreate_heap (executable_path); | ||
| 93 | need_to_recreate_heap = FALSE; | ||
| 94 | } | ||
| 95 | |||
| 96 | /* The default behavior is to treat files as binary and patch up | ||
| 97 | text files appropriately, in accordance with the MSDOS code. */ | ||
| 98 | _fmode = O_BINARY; | ||
| 99 | |||
| 100 | /* This prevents ctrl-c's in shells running while we're suspended from | ||
| 101 | having us exit. */ | ||
| 102 | SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE); | ||
| 103 | |||
| 104 | /* Invoke the NT CRT startup routine now that our housecleaning | ||
| 105 | is finished. */ | ||
| 106 | mainCRTStartup (); | ||
| 107 | } | ||
| 108 | |||
| 109 | /* Dump out .data and .bss sections into a new exectubale. */ | ||
| 110 | void | ||
| 111 | unexec (char *new_name, char *old_name, void *start_data, void *start_bss, | ||
| 112 | void *entry_address) | ||
| 113 | { | ||
| 114 | file_data in_file, out_file; | ||
| 115 | char out_filename[MAX_PATH], in_filename[MAX_PATH]; | ||
| 116 | unsigned long size; | ||
| 117 | char *ptr; | ||
| 118 | |||
| 119 | /* Make sure that the input and output filenames have the | ||
| 120 | ".exe" extension...patch them up if they don't. */ | ||
| 121 | strcpy (in_filename, old_name); | ||
| 122 | ptr = in_filename + strlen (in_filename) - 4; | ||
| 123 | if (strcmp (ptr, ".exe")) | ||
| 124 | strcat (in_filename, ".exe"); | ||
| 125 | |||
| 126 | strcpy (out_filename, new_name); | ||
| 127 | ptr = out_filename + strlen (out_filename) - 4; | ||
| 128 | if (strcmp (ptr, ".exe")) | ||
| 129 | strcat (out_filename, ".exe"); | ||
| 130 | |||
| 131 | printf ("Dumping from %s\n", in_filename); | ||
| 132 | printf (" to %s\n", out_filename); | ||
| 133 | |||
| 134 | /* We need to round off our heap to NT's allocation unit (64KB). */ | ||
| 135 | round_heap (get_allocation_unit ()); | ||
| 136 | |||
| 137 | /* Open the undumped executable file. */ | ||
| 138 | open_input_file (&in_file, in_filename); | ||
| 139 | |||
| 140 | /* Get the interesting section info, like start and size of .bss... */ | ||
| 141 | get_section_info (&in_file); | ||
| 142 | |||
| 143 | /* The size of the dumped executable is the size of the original | ||
| 144 | executable plus the size of the heap and the size of the .bss section. */ | ||
| 145 | heap_index_in_executable = round_to_next (in_file.size, | ||
| 146 | get_allocation_unit ()); | ||
| 147 | size = heap_index_in_executable + get_committed_heap_size () + bss_size; | ||
| 148 | open_output_file (&out_file, out_filename, size); | ||
| 149 | |||
| 150 | /* Set the flag (before dumping). */ | ||
| 151 | need_to_recreate_heap = TRUE; | ||
| 152 | |||
| 153 | copy_executable_and_dump_data_section (&in_file, &out_file); | ||
| 154 | dump_bss_and_heap (&in_file, &out_file); | ||
| 155 | |||
| 156 | close_file_data (&in_file); | ||
| 157 | close_file_data (&out_file); | ||
| 158 | } | ||
| 159 | |||
| 160 | |||
| 161 | /* File handling. */ | ||
| 162 | |||
| 163 | |||
| 164 | void | ||
| 165 | open_input_file (file_data *p_file, char *filename) | ||
| 166 | { | ||
| 167 | HANDLE file; | ||
| 168 | HANDLE file_mapping; | ||
| 169 | void *file_base; | ||
| 170 | unsigned long size, upper_size; | ||
| 171 | |||
| 172 | file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL, | ||
| 173 | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); | ||
| 174 | if (file == INVALID_HANDLE_VALUE) | ||
| 175 | { | ||
| 176 | printf ("Failed to open %s (%d)...bailing.\n", | ||
| 177 | filename, GetLastError ()); | ||
| 178 | exit (1); | ||
| 179 | } | ||
| 180 | |||
| 181 | size = GetFileSize (file, &upper_size); | ||
| 182 | file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY, | ||
| 183 | 0, size, NULL); | ||
| 184 | if (!file_mapping) | ||
| 185 | { | ||
| 186 | printf ("Failed to create file mapping of %s (%d)...bailing.\n", | ||
| 187 | filename, GetLastError ()); | ||
| 188 | exit (1); | ||
| 189 | } | ||
| 190 | |||
| 191 | file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size); | ||
| 192 | if (file_base == 0) | ||
| 193 | { | ||
| 194 | printf ("Failed to map view of file of %s (%d)...bailing.\n", | ||
| 195 | filename, GetLastError ()); | ||
| 196 | exit (1); | ||
| 197 | } | ||
| 198 | |||
| 199 | p_file->name = filename; | ||
| 200 | p_file->size = size; | ||
| 201 | p_file->file = file; | ||
| 202 | p_file->file_mapping = file_mapping; | ||
| 203 | p_file->file_base = file_base; | ||
| 204 | } | ||
| 205 | |||
| 206 | void | ||
| 207 | open_output_file (file_data *p_file, char *filename, unsigned long size) | ||
| 208 | { | ||
| 209 | HANDLE file; | ||
| 210 | HANDLE file_mapping; | ||
| 211 | void *file_base; | ||
| 212 | |||
| 213 | file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, | ||
| 214 | CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); | ||
| 215 | if (file == INVALID_HANDLE_VALUE) | ||
| 216 | { | ||
| 217 | printf ("open_output_file: Failed to open %s (%d).\n", | ||
| 218 | filename, GetLastError ()); | ||
| 219 | exit (1); | ||
| 220 | } | ||
| 221 | |||
| 222 | file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE, | ||
| 223 | 0, size, NULL); | ||
| 224 | if (!file_mapping) | ||
| 225 | { | ||
| 226 | printf ("open_output_file: Failed to create file mapping of %s (%d).\n", | ||
| 227 | filename, GetLastError ()); | ||
| 228 | exit (1); | ||
| 229 | } | ||
| 230 | |||
| 231 | file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size); | ||
| 232 | if (file_base == 0) | ||
| 233 | { | ||
| 234 | printf ("open_output_file: Failed to map view of file of %s (%d).\n", | ||
| 235 | filename, GetLastError ()); | ||
| 236 | exit (1); | ||
| 237 | } | ||
| 238 | |||
| 239 | p_file->name = filename; | ||
| 240 | p_file->size = size; | ||
| 241 | p_file->file = file; | ||
| 242 | p_file->file_mapping = file_mapping; | ||
| 243 | p_file->file_base = file_base; | ||
| 244 | } | ||
| 245 | |||
| 246 | /* Close the system structures associated with the given file. */ | ||
| 247 | static void | ||
| 248 | close_file_data (file_data *p_file) | ||
| 249 | { | ||
| 250 | UnmapViewOfFile (p_file->file_base); | ||
| 251 | CloseHandle (p_file->file_mapping); | ||
| 252 | CloseHandle (p_file->file); | ||
| 253 | } | ||
| 254 | |||
| 255 | |||
| 256 | /* Routines to manipulate NT executable file sections. */ | ||
| 257 | |||
| 258 | |||
| 259 | static unsigned long | ||
| 260 | get_section_size (PIMAGE_SECTION_HEADER p_section) | ||
| 261 | { | ||
| 262 | /* The section size is in different locations in the different versions. */ | ||
| 263 | switch (get_nt_minor_version ()) | ||
| 264 | { | ||
| 265 | case 10: | ||
| 266 | return p_section->SizeOfRawData; | ||
| 267 | default: | ||
| 268 | return p_section->Misc.VirtualSize; | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | /* Flip through the executable and cache the info necessary for dumping. */ | ||
| 273 | static void | ||
| 274 | get_section_info (file_data *p_infile) | ||
| 275 | { | ||
| 276 | PIMAGE_DOS_HEADER dos_header; | ||
| 277 | PIMAGE_NT_HEADERS nt_header; | ||
| 278 | PIMAGE_SECTION_HEADER section; | ||
| 279 | unsigned char *ptr; | ||
| 280 | int i; | ||
| 281 | |||
| 282 | dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base; | ||
| 283 | if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) | ||
| 284 | { | ||
| 285 | printf ("Unknown EXE header in %s...bailing.\n", p_infile->name); | ||
| 286 | exit (1); | ||
| 287 | } | ||
| 288 | nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) + | ||
| 289 | dos_header->e_lfanew); | ||
| 290 | if (nt_header == NULL) | ||
| 291 | { | ||
| 292 | printf ("Failed to find IMAGE_NT_HEADER in %s...bailing.\n", | ||
| 293 | p_infile->name); | ||
| 294 | exit (1); | ||
| 295 | } | ||
| 296 | |||
| 297 | /* Check the NT header signature ... */ | ||
| 298 | if (nt_header->Signature != IMAGE_NT_SIGNATURE) | ||
| 299 | { | ||
| 300 | printf ("Invalid IMAGE_NT_SIGNATURE 0x%x in %s...bailing.\n", | ||
| 301 | nt_header->Signature, p_infile->name); | ||
| 302 | } | ||
| 303 | |||
| 304 | /* Flip through the sections for .data and .bss ... */ | ||
| 305 | section = (PIMAGE_SECTION_HEADER) IMAGE_FIRST_SECTION (nt_header); | ||
| 306 | for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) | ||
| 307 | { | ||
| 308 | if (!strcmp (section->Name, ".bss")) | ||
| 309 | { | ||
| 310 | /* The .bss section. */ | ||
| 311 | ptr = (char *) nt_header->OptionalHeader.ImageBase + | ||
| 312 | section->VirtualAddress; | ||
| 313 | bss_start = ptr; | ||
| 314 | bss_size = get_section_size (section); | ||
| 315 | } | ||
| 316 | if (!strcmp (section->Name, ".data")) | ||
| 317 | { | ||
| 318 | /* The .data section. */ | ||
| 319 | ptr = (char *) nt_header->OptionalHeader.ImageBase + | ||
| 320 | section->VirtualAddress; | ||
| 321 | data_start_va = ptr; | ||
| 322 | data_start_file = section->PointerToRawData; | ||
| 323 | data_size = get_section_size (section); | ||
| 324 | } | ||
| 325 | section++; | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | |||
| 330 | /* The dump routines. */ | ||
| 331 | |||
| 332 | static void | ||
| 333 | copy_executable_and_dump_data_section (file_data *p_infile, | ||
| 334 | file_data *p_outfile) | ||
| 335 | { | ||
| 336 | unsigned char *data_file, *data_va; | ||
| 337 | unsigned long size, index; | ||
| 338 | |||
| 339 | /* Get a pointer to where the raw data should go in the executable file. */ | ||
| 340 | data_file = (char *) p_outfile->file_base + data_start_file; | ||
| 341 | |||
| 342 | /* Get a pointer to the raw data in our address space. */ | ||
| 343 | data_va = data_start_va; | ||
| 344 | |||
| 345 | size = (DWORD) data_file - (DWORD) p_outfile->file_base; | ||
| 346 | printf ("Copying executable up to data section...\n"); | ||
| 347 | printf ("\t0x%08x Offset in input file.\n", 0); | ||
| 348 | printf ("\t0x%08x Offset in output file.\n", 0); | ||
| 349 | printf ("\t0x%08x Size in bytes.\n", size); | ||
| 350 | memcpy (p_outfile->file_base, p_infile->file_base, size); | ||
| 351 | |||
| 352 | size = data_size; | ||
| 353 | printf ("Dumping .data section...\n"); | ||
| 354 | printf ("\t0x%08x Address in process.\n", data_va); | ||
| 355 | printf ("\t0x%08x Offset in output file.\n", | ||
| 356 | data_file - p_outfile->file_base); | ||
| 357 | printf ("\t0x%08x Size in bytes.\n", size); | ||
| 358 | memcpy (data_file, data_va, size); | ||
| 359 | |||
| 360 | index = (DWORD) data_file + size - (DWORD) p_outfile->file_base; | ||
| 361 | size = p_infile->size - index; | ||
| 362 | printf ("Copying rest of executable...\n"); | ||
| 363 | printf ("\t0x%08x Offset in input file.\n", index); | ||
| 364 | printf ("\t0x%08x Offset in output file.\n", index); | ||
| 365 | printf ("\t0x%08x Size in bytes.\n", size); | ||
| 366 | memcpy ((char *) p_outfile->file_base + index, | ||
| 367 | (char *) p_infile->file_base + index, size); | ||
| 368 | } | ||
| 369 | |||
| 370 | static void | ||
| 371 | dump_bss_and_heap (file_data *p_infile, file_data *p_outfile) | ||
| 372 | { | ||
| 373 | unsigned char *heap_data, *bss_data; | ||
| 374 | unsigned long size, index; | ||
| 375 | |||
| 376 | printf ("Dumping heap into executable...\n"); | ||
| 377 | |||
| 378 | index = heap_index_in_executable; | ||
| 379 | size = get_committed_heap_size (); | ||
| 380 | heap_data = get_heap_start (); | ||
| 381 | |||
| 382 | printf ("\t0x%08x Heap start in process.\n", heap_data); | ||
| 383 | printf ("\t0x%08x Heap offset in executable.\n", index); | ||
| 384 | printf ("\t0x%08x Heap size in bytes.\n", size); | ||
| 385 | |||
| 386 | memcpy ((PUCHAR) p_outfile->file_base + index, heap_data, size); | ||
| 387 | |||
| 388 | printf ("Dumping .bss into executable...\n"); | ||
| 389 | |||
| 390 | index += size; | ||
| 391 | size = bss_size; | ||
| 392 | bss_data = bss_start; | ||
| 393 | |||
| 394 | printf ("\t0x%08x BSS start in process.\n", bss_data); | ||
| 395 | printf ("\t0x%08x BSS offset in executable.\n", index); | ||
| 396 | printf ("\t0x%08x BSS size in bytes.\n", size); | ||
| 397 | memcpy ((char *) p_outfile->file_base + index, bss_data, size); | ||
| 398 | } | ||
| 399 | |||
| 400 | |||
| 401 | /* Reload and remap routines. */ | ||
| 402 | |||
| 403 | |||
| 404 | /* Load the dumped .bss section into the .bss area of our address space. */ | ||
| 405 | void | ||
| 406 | read_in_bss (char *filename) | ||
| 407 | { | ||
| 408 | HANDLE file; | ||
| 409 | unsigned long size, index, n_read, total_read; | ||
| 410 | char buffer[512], *bss; | ||
| 411 | int i; | ||
| 412 | |||
| 413 | file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL, | ||
| 414 | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); | ||
| 415 | if (file == INVALID_HANDLE_VALUE) | ||
| 416 | { | ||
| 417 | i = GetLastError (); | ||
| 418 | exit (1); | ||
| 419 | } | ||
| 420 | |||
| 421 | /* Seek to where the .bss section is tucked away after the heap... */ | ||
| 422 | index = heap_index_in_executable + get_committed_heap_size (); | ||
| 423 | if (SetFilePointer (file, index, NULL, FILE_BEGIN) == 0xFFFFFFFF) | ||
| 424 | { | ||
| 425 | i = GetLastError (); | ||
| 426 | exit (1); | ||
| 427 | } | ||
| 428 | |||
| 429 | |||
| 430 | /* Ok, read in the saved .bss section and initialize all | ||
| 431 | uninitialized variables. */ | ||
| 432 | total_read = 0; | ||
| 433 | size = bss_size; | ||
| 434 | bss = bss_start; | ||
| 435 | while (ReadFile (file, buffer, 512, &n_read, NULL)) | ||
| 436 | { | ||
| 437 | if (n_read == 0) | ||
| 438 | break; | ||
| 439 | memcpy (bss, buffer, n_read); | ||
| 440 | bss += n_read; | ||
| 441 | total_read += n_read; | ||
| 442 | } | ||
| 443 | |||
| 444 | CloseHandle (file); | ||
| 445 | } | ||
| 446 | |||
| 447 | /* Map the heap dumped into the executable file into our address space. */ | ||
| 448 | void | ||
| 449 | map_in_heap (char *filename) | ||
| 450 | { | ||
| 451 | HANDLE file; | ||
| 452 | HANDLE file_mapping; | ||
| 453 | void *file_base; | ||
| 454 | unsigned long size, upper_size; | ||
| 455 | int i; | ||
| 456 | |||
| 457 | file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL, | ||
| 458 | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); | ||
| 459 | if (file == INVALID_HANDLE_VALUE) | ||
| 460 | { | ||
| 461 | i = GetLastError (); | ||
| 462 | exit (1); | ||
| 463 | } | ||
| 464 | |||
| 465 | size = GetFileSize (file, &upper_size); | ||
| 466 | file_mapping = CreateFileMapping (file, NULL, PAGE_WRITECOPY, | ||
| 467 | 0, size, NULL); | ||
| 468 | if (!file_mapping) | ||
| 469 | { | ||
| 470 | i = GetLastError (); | ||
| 471 | exit (1); | ||
| 472 | } | ||
| 473 | |||
| 474 | size = get_committed_heap_size (); | ||
| 475 | file_base = MapViewOfFileEx (file_mapping, FILE_MAP_COPY, 0, | ||
| 476 | heap_index_in_executable, size, | ||
| 477 | get_heap_start ()); | ||
| 478 | if (file_base == 0) | ||
| 479 | { | ||
| 480 | i = GetLastError (); | ||
| 481 | exit (1); | ||
| 482 | } | ||
| 483 | } | ||