Port to certain Android environments with no GUI
[emacs.git] / src / unexw32.c
blobd8329be522da80888eade1c5f55638451d56ac23
1 /* unexec for GNU Emacs on Windows NT.
2 Copyright (C) 1994, 2001-2024 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
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 3 of the License, or (at
9 your option) any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
20 Geoff Voelker (voelker@cs.washington.edu) 8-12-94
23 #include <config.h>
24 #include "unexec.h"
25 #include "lisp.h"
26 #include "w32common.h"
27 #include "w32.h"
29 #include <stdio.h>
30 #include <fcntl.h>
31 #include <time.h>
32 #include <windows.h>
34 /* Include relevant definitions from IMAGEHLP.H, which can be found
35 in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
37 PIMAGE_NT_HEADERS (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
38 DWORD FileLength,
39 LPDWORD HeaderSum,
40 LPDWORD CheckSum);
42 extern char my_begdata[];
43 extern char my_begbss[];
44 extern char *my_begbss_static;
46 #include "w32heap.h"
48 void get_section_info (file_data *p_file);
49 void copy_executable_and_dump_data (file_data *, file_data *);
50 void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile);
52 /* Cached info about the .data section in the executable. */
53 PIMAGE_SECTION_HEADER data_section;
54 PCHAR data_start = 0;
55 DWORD_PTR data_size = 0;
57 /* Cached info about the .bss section in the executable. */
58 PIMAGE_SECTION_HEADER bss_section;
59 PCHAR bss_start = 0;
60 DWORD_PTR bss_size = 0;
61 DWORD_PTR extra_bss_size = 0;
62 /* bss data that is static might be discontiguous from non-static. */
63 PIMAGE_SECTION_HEADER bss_section_static;
64 PCHAR bss_start_static = 0;
65 DWORD_PTR bss_size_static = 0;
66 DWORD_PTR extra_bss_size_static = 0;
68 /* File handling. */
70 /* Implementation note: this and the next functions work with ANSI
71 codepage encoded file names! */
73 int
74 open_output_file (file_data *p_file, char *filename, unsigned long size)
76 HANDLE file;
77 HANDLE file_mapping;
78 void *file_base;
80 /* We delete any existing FILENAME because loadup.el will create a
81 hard link to it under the name emacs-XX.YY.ZZ.nn.exe. Evidently,
82 overwriting a file on Unix breaks any hard links to it, but that
83 doesn't happen on Windows. If we don't delete the file before
84 creating it, all the emacs-XX.YY.ZZ.nn.exe end up being hard
85 links to the same file, which defeats the purpose of these hard
86 links: being able to run previous builds. */
87 DeleteFileA (filename);
88 file = CreateFileA (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
89 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
90 if (file == INVALID_HANDLE_VALUE)
91 return FALSE;
93 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
94 0, size, NULL);
95 if (!file_mapping)
96 return FALSE;
98 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
99 if (file_base == 0)
100 return FALSE;
102 p_file->name = filename;
103 p_file->size = size;
104 p_file->file = file;
105 p_file->file_mapping = file_mapping;
106 p_file->file_base = file_base;
108 return TRUE;
112 /* Routines to manipulate NT executable file sections. */
114 /* Return pointer to section header for named section. */
115 IMAGE_SECTION_HEADER *
116 find_section (const char * name, IMAGE_NT_HEADERS * nt_header)
118 PIMAGE_SECTION_HEADER section;
119 int i;
121 section = IMAGE_FIRST_SECTION (nt_header);
123 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
125 if (strcmp ((char *)section->Name, name) == 0)
126 return section;
127 section++;
129 return NULL;
132 #if 0 /* unused */
133 /* Return pointer to section header for section containing the given
134 offset in its raw data area. */
135 static IMAGE_SECTION_HEADER *
136 offset_to_section (DWORD_PTR offset, IMAGE_NT_HEADERS * nt_header)
138 PIMAGE_SECTION_HEADER section;
139 int i;
141 section = IMAGE_FIRST_SECTION (nt_header);
143 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
145 if (offset >= section->PointerToRawData
146 && offset < section->PointerToRawData + section->SizeOfRawData)
147 return section;
148 section++;
150 return NULL;
152 #endif
154 /* Return offset to an object in dst, given offset in src. We assume
155 there is at least one section in both src and dst images, and that
156 the some sections may have been added to dst (after sections in src). */
157 static DWORD_PTR
158 relocate_offset (DWORD_PTR offset,
159 IMAGE_NT_HEADERS * src_nt_header,
160 IMAGE_NT_HEADERS * dst_nt_header)
162 PIMAGE_SECTION_HEADER src_section = IMAGE_FIRST_SECTION (src_nt_header);
163 PIMAGE_SECTION_HEADER dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
164 int i = 0;
166 while (offset >= src_section->PointerToRawData)
168 if (offset < src_section->PointerToRawData + src_section->SizeOfRawData)
169 break;
170 i++;
171 if (i == src_nt_header->FileHeader.NumberOfSections)
173 /* Handle offsets after the last section. */
174 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
175 dst_section += dst_nt_header->FileHeader.NumberOfSections - 1;
176 while (dst_section->PointerToRawData == 0)
177 dst_section--;
178 while (src_section->PointerToRawData == 0)
179 src_section--;
180 return offset
181 + (dst_section->PointerToRawData + dst_section->SizeOfRawData)
182 - (src_section->PointerToRawData + src_section->SizeOfRawData);
184 src_section++;
185 dst_section++;
187 return offset +
188 (dst_section->PointerToRawData - src_section->PointerToRawData);
191 #define RVA_TO_OFFSET(rva, section) \
192 ((section)->PointerToRawData + ((DWORD_PTR)(rva) - (section)->VirtualAddress))
194 #define RVA_TO_SECTION_OFFSET(rva, section) \
195 ((DWORD_PTR)(rva) - (section)->VirtualAddress)
197 /* Convert address in executing image to RVA. */
198 #define PTR_TO_RVA(ptr) ((DWORD_PTR)(ptr) - (DWORD_PTR) GetModuleHandle (NULL))
200 #define PTR_TO_OFFSET(ptr, pfile_data) \
201 ((unsigned char *)(ptr) - (pfile_data)->file_base)
203 #define OFFSET_TO_PTR(offset, pfile_data) \
204 ((pfile_data)->file_base + (DWORD_PTR)(offset))
206 #if 0 /* unused */
207 #define OFFSET_TO_RVA(offset, section) \
208 ((section)->VirtualAddress + ((DWORD_PTR)(offset) - (section)->PointerToRawData))
210 #define RVA_TO_PTR(var,section,filedata) \
211 ((unsigned char *)(RVA_TO_OFFSET (var,section) + (filedata).file_base))
212 #endif
215 /* Flip through the executable and cache the info necessary for dumping. */
216 void
217 get_section_info (file_data *p_infile)
219 PIMAGE_DOS_HEADER dos_header;
220 PIMAGE_NT_HEADERS nt_header;
221 int overlap;
223 dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
224 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
226 printf ("Unknown EXE header in %s...bailing.\n", p_infile->name);
227 exit (1);
229 nt_header = (PIMAGE_NT_HEADERS) (((DWORD_PTR) dos_header) +
230 dos_header->e_lfanew);
231 if (nt_header == NULL)
233 printf ("Failed to find IMAGE_NT_HEADER in %s...bailing.\n",
234 p_infile->name);
235 exit (1);
238 /* Check the NT header signature ... */
239 if (nt_header->Signature != IMAGE_NT_SIGNATURE)
241 printf ("Invalid IMAGE_NT_SIGNATURE 0x%lx in %s...bailing.\n",
242 nt_header->Signature, p_infile->name);
243 exit (1);
246 /* Locate the ".data" and ".bss" sections for Emacs. (Note that the
247 actual section names are probably different from these, and might
248 actually be the same section.)
250 We do this as follows: first we determine the virtual address
251 ranges in this process for the data and bss variables that we wish
252 to preserve. Then we map these VAs to the section entries in the
253 source image. Finally, we determine the new size of the raw data
254 area for the bss section, so we can make the new image the correct
255 size. */
257 /* We arrange for the Emacs initialized data to be in a separate
258 section if possible, because we cannot rely on my_begdata and
259 my_edata marking out the full extent of the initialized data, at
260 least on the Alpha where the linker freely reorders variables
261 across libraries. If we can arrange for this, all we need to do is
262 find the start and size of the EMDATA section. */
263 data_section = find_section ("EMDATA", nt_header);
264 if (data_section)
266 data_start = (char *) nt_header->OptionalHeader.ImageBase +
267 data_section->VirtualAddress;
268 data_size = data_section->Misc.VirtualSize;
270 else
272 /* Fallback on the old method if compiler doesn't support the
273 data_set #pragma (or its equivalent). */
274 data_start = my_begdata;
275 data_size = my_edata - my_begdata;
276 data_section = rva_to_section (PTR_TO_RVA (my_begdata), nt_header);
277 if (data_section != rva_to_section (PTR_TO_RVA (my_edata), nt_header))
279 printf ("Initialized data is not in a single section...bailing\n");
280 exit (1);
284 /* As noted in lastfile.c, the Alpha (but not the Intel) MSVC linker
285 globally segregates all static and public bss data (ie. across all
286 linked modules, not just per module), so we must take both static
287 and public bss areas into account to determine the true extent of
288 the bss area used by Emacs.
290 To be strictly correct, we dump the static and public bss areas
291 used by Emacs separately if non-overlapping (since otherwise we are
292 dumping bss data belonging to system libraries, eg. the static bss
293 system data on the Alpha). */
295 bss_start = my_begbss;
296 bss_size = my_endbss - my_begbss;
297 bss_section = rva_to_section (PTR_TO_RVA (my_begbss), nt_header);
298 if (bss_section != rva_to_section (PTR_TO_RVA (my_endbss), nt_header))
300 printf ("Uninitialized data is not in a single section...bailing\n");
301 exit (1);
303 /* Compute how much the .bss section's raw data will grow. */
304 extra_bss_size =
305 ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss), bss_section),
306 nt_header->OptionalHeader.FileAlignment)
307 - bss_section->SizeOfRawData;
309 bss_start_static = my_begbss_static;
310 bss_size_static = my_endbss_static - my_begbss_static;
311 bss_section_static = rva_to_section (PTR_TO_RVA (my_begbss_static), nt_header);
312 if (bss_section_static != rva_to_section (PTR_TO_RVA (my_endbss_static), nt_header))
314 printf ("Uninitialized static data is not in a single section...bailing\n");
315 exit (1);
317 /* Compute how much the static .bss section's raw data will grow. */
318 extra_bss_size_static =
319 ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss_static), bss_section_static),
320 nt_header->OptionalHeader.FileAlignment)
321 - bss_section_static->SizeOfRawData;
323 /* Combine the bss sections into one if they overlap. */
324 #ifdef _ALPHA_
325 overlap = 1; /* force all bss data to be dumped */
326 #else
327 overlap = 0;
328 #endif
329 if (bss_start < bss_start_static)
331 if (bss_start_static < bss_start + bss_size)
332 overlap = 1;
334 else
336 if (bss_start < bss_start_static + bss_size_static)
337 overlap = 1;
339 if (overlap)
341 if (bss_section != bss_section_static)
343 printf ("BSS data not in a single section...bailing\n");
344 exit (1);
346 bss_start = min (bss_start, bss_start_static);
347 bss_size = max (my_endbss, my_endbss_static) - bss_start;
348 bss_section_static = 0;
349 extra_bss_size = max (extra_bss_size, extra_bss_size_static);
350 extra_bss_size_static = 0;
354 /* Format to print a DWORD_PTR value. */
355 #if defined MINGW_W64 && defined _WIN64
356 # define pDWP "16llx"
357 #else
358 # define pDWP "08lx"
359 #endif
361 /* The dump routines. */
363 void
364 copy_executable_and_dump_data (file_data *p_infile,
365 file_data *p_outfile)
367 unsigned char *dst, *dst_save;
368 PIMAGE_DOS_HEADER dos_header;
369 PIMAGE_NT_HEADERS nt_header;
370 PIMAGE_NT_HEADERS dst_nt_header;
371 PIMAGE_SECTION_HEADER section;
372 PIMAGE_SECTION_HEADER dst_section;
373 DWORD_PTR offset;
374 int i;
375 int be_verbose = GetEnvironmentVariable ("DEBUG_DUMP", NULL, 0) > 0;
377 #define COPY_CHUNK(message, src, size, verbose) \
378 do { \
379 unsigned char *s = (void *)(src); \
380 DWORD_PTR count = (size); \
381 if (verbose) \
383 printf ("%s\n", (message)); \
384 printf ("\t0x%"pDWP" Offset in input file.\n", (DWORD_PTR)(s - p_infile->file_base)); \
385 printf ("\t0x%"pDWP" Offset in output file.\n", (DWORD_PTR)(dst - p_outfile->file_base)); \
386 printf ("\t0x%"pDWP" Size in bytes.\n", count); \
388 memcpy (dst, s, count); \
389 dst += count; \
390 } while (0)
392 #define COPY_PROC_CHUNK(message, src, size, verbose) \
393 do { \
394 unsigned char *s = (void *)(src); \
395 DWORD_PTR count = (size); \
396 if (verbose) \
398 printf ("%s\n", (message)); \
399 printf ("\t0x%p Address in process.\n", s); \
400 printf ("\t0x%p Base output file.\n", p_outfile->file_base); \
401 printf ("\t0x%"pDWP" Offset in output file.\n", (DWORD_PTR)(dst - p_outfile->file_base)); \
402 printf ("\t0x%p Address in output file.\n", dst); \
403 printf ("\t0x%"pDWP" Size in bytes.\n", count); \
405 memcpy (dst, s, count); \
406 dst += count; \
407 } while (0)
409 #define DST_TO_OFFSET() PTR_TO_OFFSET (dst, p_outfile)
410 #define ROUND_UP_DST(align) \
411 (dst = p_outfile->file_base + ROUND_UP (DST_TO_OFFSET (), (align)))
412 #define ROUND_UP_DST_AND_ZERO(align) \
413 do { \
414 unsigned char *newdst = p_outfile->file_base \
415 + ROUND_UP (DST_TO_OFFSET (), (align)); \
416 /* Zero the alignment slop; it may actually initialize real data. */ \
417 memset (dst, 0, newdst - dst); \
418 dst = newdst; \
419 } while (0)
421 /* Copy the source image sequentially, ie. section by section after
422 copying the headers and section table, to simplify the process of
423 dumping the raw data for the bss and heap sections.
425 Note that dst is updated implicitly by each COPY_CHUNK. */
427 dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
428 nt_header = (PIMAGE_NT_HEADERS) (((DWORD_PTR) dos_header) +
429 dos_header->e_lfanew);
430 section = IMAGE_FIRST_SECTION (nt_header);
432 dst = (unsigned char *) p_outfile->file_base;
434 COPY_CHUNK ("Copying DOS header...", dos_header,
435 (DWORD_PTR) nt_header - (DWORD_PTR) dos_header, be_verbose);
436 dst_nt_header = (PIMAGE_NT_HEADERS) dst;
437 COPY_CHUNK ("Copying NT header...", nt_header,
438 (DWORD_PTR) section - (DWORD_PTR) nt_header, be_verbose);
439 dst_section = (PIMAGE_SECTION_HEADER) dst;
440 COPY_CHUNK ("Copying section table...", section,
441 nt_header->FileHeader.NumberOfSections * sizeof (*section),
442 be_verbose);
444 /* Align the first section's raw data area, and set the header size
445 field accordingly. */
446 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
447 dst_nt_header->OptionalHeader.SizeOfHeaders = DST_TO_OFFSET ();
449 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
451 char msg[100];
452 /* Windows section names are fixed 8-char strings, only
453 zero-terminated if the name is shorter than 8 characters. */
454 sprintf (msg, "Copying raw data for %.8s...", section->Name);
456 dst_save = dst;
458 /* Update the file-relative offset for this section's raw data (if
459 it has any) in case things have been relocated; we will update
460 the other offsets below once we know where everything is. */
461 if (dst_section->PointerToRawData)
462 dst_section->PointerToRawData = DST_TO_OFFSET ();
464 /* Can always copy the original raw data. */
465 COPY_CHUNK
466 (msg, OFFSET_TO_PTR (section->PointerToRawData, p_infile),
467 section->SizeOfRawData, be_verbose);
468 /* Ensure alignment slop is zeroed. */
469 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
471 /* Note that various sections below may be aliases. */
472 if (section == data_section)
474 dst = dst_save
475 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (data_start), dst_section);
476 COPY_PROC_CHUNK ("Dumping initialized data...",
477 data_start, data_size, be_verbose);
478 dst = dst_save + dst_section->SizeOfRawData;
480 if (section == bss_section)
482 /* Dump contents of bss variables, adjusting the section's raw
483 data size as necessary. */
484 dst = dst_save
485 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start), dst_section);
486 COPY_PROC_CHUNK ("Dumping bss data...", bss_start,
487 bss_size, be_verbose);
488 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
489 dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
490 /* Determine new size of raw data area. */
491 dst = max (dst, dst_save + dst_section->SizeOfRawData);
492 dst_section->SizeOfRawData = dst - dst_save;
493 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
494 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
496 if (section == bss_section_static)
498 /* Dump contents of static bss variables, adjusting the
499 section's raw data size as necessary. */
500 dst = dst_save
501 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start_static), dst_section);
502 COPY_PROC_CHUNK ("Dumping static bss data...", bss_start_static,
503 bss_size_static, be_verbose);
504 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
505 dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
506 /* Determine new size of raw data area. */
507 dst = max (dst, dst_save + dst_section->SizeOfRawData);
508 dst_section->SizeOfRawData = dst - dst_save;
509 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
510 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
513 /* Align the section's raw data area. */
514 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
516 section++;
517 dst_section++;
520 /* Copy remainder of source image. */
522 section--;
523 while (section->PointerToRawData == 0);
524 offset = ROUND_UP (section->PointerToRawData + section->SizeOfRawData,
525 nt_header->OptionalHeader.FileAlignment);
526 COPY_CHUNK
527 ("Copying remainder of executable...",
528 OFFSET_TO_PTR (offset, p_infile),
529 p_infile->size - offset, be_verbose);
531 /* Final size for new image. */
532 p_outfile->size = DST_TO_OFFSET ();
534 /* Now patch up remaining file-relative offsets. */
535 section = IMAGE_FIRST_SECTION (nt_header);
536 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
538 #define ADJUST_OFFSET(var) \
539 do { \
540 if ((var) != 0) \
541 (var) = relocate_offset ((var), nt_header, dst_nt_header); \
542 } while (0)
544 dst_nt_header->OptionalHeader.SizeOfInitializedData = 0;
545 dst_nt_header->OptionalHeader.SizeOfUninitializedData = 0;
546 for (i = 0; i < dst_nt_header->FileHeader.NumberOfSections; i++)
548 /* Recompute data sizes for completeness. */
549 if (dst_section[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
550 dst_nt_header->OptionalHeader.SizeOfInitializedData +=
551 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
552 else if (dst_section[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
553 dst_nt_header->OptionalHeader.SizeOfUninitializedData +=
554 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
556 ADJUST_OFFSET (dst_section[i].PointerToLinenumbers);
559 ADJUST_OFFSET (dst_nt_header->FileHeader.PointerToSymbolTable);
561 /* Update offsets in debug directory entries. */
563 IMAGE_DATA_DIRECTORY debug_dir =
564 dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
565 PIMAGE_DEBUG_DIRECTORY debug_entry;
567 section = rva_to_section (debug_dir.VirtualAddress, dst_nt_header);
568 if (section)
570 debug_entry = (PIMAGE_DEBUG_DIRECTORY)
571 (RVA_TO_OFFSET (debug_dir.VirtualAddress, section) + p_outfile->file_base);
572 debug_dir.Size /= sizeof (IMAGE_DEBUG_DIRECTORY);
574 for (i = 0; i < debug_dir.Size; i++, debug_entry++)
575 ADJUST_OFFSET (debug_entry->PointerToRawData);
581 /* Dump out .data and .bss sections into a new executable. */
582 void
583 unexec (const char *new_name, const char *old_name)
585 file_data in_file, out_file;
586 char out_filename[MAX_PATH], in_filename[MAX_PATH], new_name_a[MAX_PATH];
587 unsigned long size;
588 char *p;
589 char *q;
591 /* Ignore old_name, and get our actual location from the OS. */
592 if (!GetModuleFileNameA (NULL, in_filename, MAX_PATH))
593 abort ();
595 /* Can't use dostounix_filename here, since that needs its file name
596 argument encoded in UTF-8. */
597 for (p = in_filename; *p; p = CharNextA (p))
598 if (*p == '\\')
599 *p = '/';
601 strcpy (out_filename, in_filename);
602 filename_to_ansi (new_name, new_name_a);
604 /* Change the base of the output filename to match the requested name. */
605 if ((p = strrchr (out_filename, '/')) == NULL)
606 abort ();
607 /* The filenames have already been expanded, and will be in Unix
608 format, so it is safe to expect an absolute name. */
609 if ((q = strrchr (new_name_a, '/')) == NULL)
610 abort ();
611 strcpy (p, q);
613 #ifdef ENABLE_CHECKING
614 report_temacs_memory_usage ();
615 #endif
617 /* Make sure that the output filename has the ".exe" extension...patch
618 it up if not. */
619 p = out_filename + strlen (out_filename) - 4;
620 if (strcmp (p, ".exe"))
621 strcat (out_filename, ".exe");
623 printf ("Dumping from %s\n", in_filename);
624 printf (" to %s\n", out_filename);
626 /* Open the undumped executable file. */
627 if (!open_input_file (&in_file, in_filename))
629 printf ("Failed to open %s (%lu)...bailing.\n",
630 in_filename, GetLastError ());
631 exit (1);
634 /* Get the interesting section info, like start and size of .bss... */
635 get_section_info (&in_file);
637 /* The size of the dumped executable is the size of the original
638 executable plus the size of the heap and the size of the .bss section. */
639 size = in_file.size +
640 extra_bss_size +
641 extra_bss_size_static;
642 if (!open_output_file (&out_file, out_filename, size))
644 printf ("Failed to open %s (%lu)...bailing.\n",
645 out_filename, GetLastError ());
646 exit (1);
649 copy_executable_and_dump_data (&in_file, &out_file);
651 /* Patch up header fields; profiler is picky about this. */
653 PIMAGE_DOS_HEADER dos_header;
654 PIMAGE_NT_HEADERS nt_header;
655 HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
656 DWORD headersum;
657 DWORD checksum;
659 dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
660 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
662 nt_header->OptionalHeader.CheckSum = 0;
663 // nt_header->FileHeader.TimeDateStamp = time (NULL);
664 // dos_header->e_cp = size / 512;
665 // nt_header->OptionalHeader.SizeOfImage = size;
667 pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
668 if (pfnCheckSumMappedFile)
670 // nt_header->FileHeader.TimeDateStamp = time (NULL);
671 pfnCheckSumMappedFile (out_file.file_base,
672 out_file.size,
673 &headersum,
674 &checksum);
675 nt_header->OptionalHeader.CheckSum = checksum;
677 FreeLibrary (hImagehelp);
680 close_file_data (&in_file);
681 close_file_data (&out_file);
684 /* eof */