Merge from emacs-23; up to 2010-06-03T22:16:02Z!dann@ics.uci.edu
[bpt/emacs.git] / src / unexw32.c
1 /* unexec for GNU Emacs on Windows NT.
2 Copyright (C) 1994, 2001-2011 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 3 of the License, or
9 (at your option) 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. If not, see <http://www.gnu.org/licenses/>. */
18
19 /*
20 Geoff Voelker (voelker@cs.washington.edu) 8-12-94
21 */
22
23 #include <config.h>
24
25 #include <stdio.h>
26 #include <fcntl.h>
27 #include <time.h>
28 #include <windows.h>
29
30 /* Include relevant definitions from IMAGEHLP.H, which can be found
31 in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
32
33 PIMAGE_NT_HEADERS
34 (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
35 DWORD FileLength,
36 LPDWORD HeaderSum,
37 LPDWORD CheckSum);
38
39 extern BOOL ctrl_c_handler (unsigned long type);
40
41 extern char my_begdata[];
42 extern char my_edata[];
43 extern char my_begbss[];
44 extern char my_endbss[];
45 extern char *my_begbss_static;
46 extern char *my_endbss_static;
47
48 #include "w32heap.h"
49
50 #undef min
51 #undef max
52 #define min(x, y) (((x) < (y)) ? (x) : (y))
53 #define max(x, y) (((x) > (y)) ? (x) : (y))
54
55 /* Basically, our "initialized" flag. */
56 BOOL using_dynamic_heap = FALSE;
57
58 int open_input_file (file_data *p_file, char *name);
59 int open_output_file (file_data *p_file, char *name, unsigned long size);
60 void close_file_data (file_data *p_file);
61
62 void get_section_info (file_data *p_file);
63 void copy_executable_and_dump_data (file_data *, file_data *);
64 void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile);
65
66 /* Cached info about the .data section in the executable. */
67 PIMAGE_SECTION_HEADER data_section;
68 PCHAR data_start = 0;
69 DWORD data_size = 0;
70
71 /* Cached info about the .bss section in the executable. */
72 PIMAGE_SECTION_HEADER bss_section;
73 PCHAR bss_start = 0;
74 DWORD bss_size = 0;
75 DWORD extra_bss_size = 0;
76 /* bss data that is static might be discontiguous from non-static. */
77 PIMAGE_SECTION_HEADER bss_section_static;
78 PCHAR bss_start_static = 0;
79 DWORD bss_size_static = 0;
80 DWORD extra_bss_size_static = 0;
81
82 PIMAGE_SECTION_HEADER heap_section;
83
84 #ifdef HAVE_NTGUI
85 HINSTANCE hinst = NULL;
86 HINSTANCE hprevinst = NULL;
87 LPSTR lpCmdLine = "";
88 int nCmdShow = 0;
89 #endif /* HAVE_NTGUI */
90
91 /* Startup code for running on NT. When we are running as the dumped
92 version, we need to bootstrap our heap and .bss section into our
93 address space before we can actually hand off control to the startup
94 code supplied by NT (primarily because that code relies upon malloc ()). */
95 void
96 _start (void)
97 {
98 extern void mainCRTStartup (void);
99
100 #if 1
101 /* Give us a way to debug problems with crashes on startup when
102 running under the MSVC profiler. */
103 if (GetEnvironmentVariable ("EMACS_DEBUG", NULL, 0) > 0)
104 DebugBreak ();
105 #endif
106
107 /* Cache system info, e.g., the NT page size. */
108 cache_system_info ();
109
110 /* Grab our malloc arena space now, before CRT starts up. */
111 init_heap ();
112
113 /* This prevents ctrl-c's in shells running while we're suspended from
114 having us exit. */
115 SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE);
116
117 /* Prevent Emacs from being locked up (eg. in batch mode) when
118 accessing devices that aren't mounted (eg. removable media drives). */
119 SetErrorMode (SEM_FAILCRITICALERRORS);
120
121 /* Invoke the NT CRT startup routine now that our housecleaning
122 is finished. */
123 #ifdef HAVE_NTGUI
124 /* determine WinMain args like crt0.c does */
125 hinst = GetModuleHandle(NULL);
126 lpCmdLine = GetCommandLine();
127 nCmdShow = SW_SHOWDEFAULT;
128 #endif
129 mainCRTStartup ();
130 }
131
132
133 /* File handling. */
134
135 int
136 open_input_file (file_data *p_file, char *filename)
137 {
138 HANDLE file;
139 HANDLE file_mapping;
140 void *file_base;
141 unsigned long size, upper_size;
142
143 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
144 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
145 if (file == INVALID_HANDLE_VALUE)
146 return FALSE;
147
148 size = GetFileSize (file, &upper_size);
149 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
150 0, size, NULL);
151 if (!file_mapping)
152 return FALSE;
153
154 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
155 if (file_base == 0)
156 return FALSE;
157
158 p_file->name = filename;
159 p_file->size = size;
160 p_file->file = file;
161 p_file->file_mapping = file_mapping;
162 p_file->file_base = file_base;
163
164 return TRUE;
165 }
166
167 int
168 open_output_file (file_data *p_file, char *filename, unsigned long size)
169 {
170 HANDLE file;
171 HANDLE file_mapping;
172 void *file_base;
173
174 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
175 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
176 if (file == INVALID_HANDLE_VALUE)
177 return FALSE;
178
179 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
180 0, size, NULL);
181 if (!file_mapping)
182 return FALSE;
183
184 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
185 if (file_base == 0)
186 return FALSE;
187
188 p_file->name = filename;
189 p_file->size = size;
190 p_file->file = file;
191 p_file->file_mapping = file_mapping;
192 p_file->file_base = file_base;
193
194 return TRUE;
195 }
196
197 /* Close the system structures associated with the given file. */
198 void
199 close_file_data (file_data *p_file)
200 {
201 UnmapViewOfFile (p_file->file_base);
202 CloseHandle (p_file->file_mapping);
203 /* For the case of output files, set final size. */
204 SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN);
205 SetEndOfFile (p_file->file);
206 CloseHandle (p_file->file);
207 }
208
209
210 /* Routines to manipulate NT executable file sections. */
211
212 /* Return pointer to section header for named section. */
213 IMAGE_SECTION_HEADER *
214 find_section (char * name, IMAGE_NT_HEADERS * nt_header)
215 {
216 PIMAGE_SECTION_HEADER section;
217 int i;
218
219 section = IMAGE_FIRST_SECTION (nt_header);
220
221 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
222 {
223 if (strcmp (section->Name, name) == 0)
224 return section;
225 section++;
226 }
227 return NULL;
228 }
229
230 /* Return pointer to section header for section containing the given
231 relative virtual address. */
232 IMAGE_SECTION_HEADER *
233 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
234 {
235 PIMAGE_SECTION_HEADER section;
236 int i;
237
238 section = IMAGE_FIRST_SECTION (nt_header);
239
240 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
241 {
242 /* Some linkers (eg. the NT SDK linker I believe) swapped the
243 meaning of these two values - or rather, they ignored
244 VirtualSize entirely and always set it to zero. This affects
245 some very old exes (eg. gzip dated Dec 1993). Since
246 w32_executable_type relies on this function to work reliably,
247 we need to cope with this. */
248 DWORD real_size = max (section->SizeOfRawData,
249 section->Misc.VirtualSize);
250 if (rva >= section->VirtualAddress
251 && rva < section->VirtualAddress + real_size)
252 return section;
253 section++;
254 }
255 return NULL;
256 }
257
258 /* Return pointer to section header for section containing the given
259 offset in its raw data area. */
260 IMAGE_SECTION_HEADER *
261 offset_to_section (DWORD offset, IMAGE_NT_HEADERS * nt_header)
262 {
263 PIMAGE_SECTION_HEADER section;
264 int i;
265
266 section = IMAGE_FIRST_SECTION (nt_header);
267
268 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
269 {
270 if (offset >= section->PointerToRawData
271 && offset < section->PointerToRawData + section->SizeOfRawData)
272 return section;
273 section++;
274 }
275 return NULL;
276 }
277
278 /* Return offset to an object in dst, given offset in src. We assume
279 there is at least one section in both src and dst images, and that
280 the some sections may have been added to dst (after sections in src). */
281 DWORD
282 relocate_offset (DWORD offset,
283 IMAGE_NT_HEADERS * src_nt_header,
284 IMAGE_NT_HEADERS * dst_nt_header)
285 {
286 PIMAGE_SECTION_HEADER src_section = IMAGE_FIRST_SECTION (src_nt_header);
287 PIMAGE_SECTION_HEADER dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
288 int i = 0;
289
290 while (offset >= src_section->PointerToRawData)
291 {
292 if (offset < src_section->PointerToRawData + src_section->SizeOfRawData)
293 break;
294 i++;
295 if (i == src_nt_header->FileHeader.NumberOfSections)
296 {
297 /* Handle offsets after the last section. */
298 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
299 dst_section += dst_nt_header->FileHeader.NumberOfSections - 1;
300 while (dst_section->PointerToRawData == 0)
301 dst_section--;
302 while (src_section->PointerToRawData == 0)
303 src_section--;
304 return offset
305 + (dst_section->PointerToRawData + dst_section->SizeOfRawData)
306 - (src_section->PointerToRawData + src_section->SizeOfRawData);
307 }
308 src_section++;
309 dst_section++;
310 }
311 return offset +
312 (dst_section->PointerToRawData - src_section->PointerToRawData);
313 }
314
315 #define OFFSET_TO_RVA(offset, section) \
316 (section->VirtualAddress + ((DWORD)(offset) - section->PointerToRawData))
317
318 #define RVA_TO_OFFSET(rva, section) \
319 (section->PointerToRawData + ((DWORD)(rva) - section->VirtualAddress))
320
321 #define RVA_TO_SECTION_OFFSET(rva, section) \
322 ((DWORD)(rva) - section->VirtualAddress)
323
324 /* Convert address in executing image to RVA. */
325 #define PTR_TO_RVA(ptr) ((DWORD)(ptr) - (DWORD) GetModuleHandle (NULL))
326
327 #define RVA_TO_PTR(var,section,filedata) \
328 ((void *)(RVA_TO_OFFSET(var,section) + (filedata).file_base))
329
330 #define PTR_TO_OFFSET(ptr, pfile_data) \
331 ((unsigned char *)(ptr) - (pfile_data)->file_base)
332
333 #define OFFSET_TO_PTR(offset, pfile_data) \
334 ((pfile_data)->file_base + (DWORD)(offset))
335
336
337 /* Flip through the executable and cache the info necessary for dumping. */
338 void
339 get_section_info (file_data *p_infile)
340 {
341 PIMAGE_DOS_HEADER dos_header;
342 PIMAGE_NT_HEADERS nt_header;
343 PIMAGE_SECTION_HEADER section;
344 int overlap;
345
346 dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
347 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
348 {
349 printf ("Unknown EXE header in %s...bailing.\n", p_infile->name);
350 exit (1);
351 }
352 nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +
353 dos_header->e_lfanew);
354 if (nt_header == NULL)
355 {
356 printf ("Failed to find IMAGE_NT_HEADER in %s...bailing.\n",
357 p_infile->name);
358 exit (1);
359 }
360
361 /* Check the NT header signature ... */
362 if (nt_header->Signature != IMAGE_NT_SIGNATURE)
363 {
364 printf ("Invalid IMAGE_NT_SIGNATURE 0x%x in %s...bailing.\n",
365 nt_header->Signature, p_infile->name);
366 exit (1);
367 }
368
369 /* Locate the ".data" and ".bss" sections for Emacs. (Note that the
370 actual section names are probably different from these, and might
371 actually be the same section.)
372
373 We do this as follows: first we determine the virtual address
374 ranges in this process for the data and bss variables that we wish
375 to preserve. Then we map these VAs to the section entries in the
376 source image. Finally, we determine the new size of the raw data
377 area for the bss section, so we can make the new image the correct
378 size. */
379
380 /* We arrange for the Emacs initialized data to be in a separate
381 section if possible, because we cannot rely on my_begdata and
382 my_edata marking out the full extent of the initialized data, at
383 least on the Alpha where the linker freely reorders variables
384 across libraries. If we can arrange for this, all we need to do is
385 find the start and size of the EMDATA section. */
386 data_section = find_section ("EMDATA", nt_header);
387 if (data_section)
388 {
389 data_start = (char *) nt_header->OptionalHeader.ImageBase +
390 data_section->VirtualAddress;
391 data_size = data_section->Misc.VirtualSize;
392 }
393 else
394 {
395 /* Fallback on the old method if compiler doesn't support the
396 data_set #pragma (or its equivalent). */
397 data_start = my_begdata;
398 data_size = my_edata - my_begdata;
399 data_section = rva_to_section (PTR_TO_RVA (my_begdata), nt_header);
400 if (data_section != rva_to_section (PTR_TO_RVA (my_edata), nt_header))
401 {
402 printf ("Initialized data is not in a single section...bailing\n");
403 exit (1);
404 }
405 }
406
407 /* As noted in lastfile.c, the Alpha (but not the Intel) MSVC linker
408 globally segregates all static and public bss data (ie. across all
409 linked modules, not just per module), so we must take both static
410 and public bss areas into account to determine the true extent of
411 the bss area used by Emacs.
412
413 To be strictly correct, we dump the static and public bss areas
414 used by Emacs separately if non-overlapping (since otherwise we are
415 dumping bss data belonging to system libraries, eg. the static bss
416 system data on the Alpha). */
417
418 bss_start = my_begbss;
419 bss_size = my_endbss - my_begbss;
420 bss_section = rva_to_section (PTR_TO_RVA (my_begbss), nt_header);
421 if (bss_section != rva_to_section (PTR_TO_RVA (my_endbss), nt_header))
422 {
423 printf ("Uninitialized data is not in a single section...bailing\n");
424 exit (1);
425 }
426 /* Compute how much the .bss section's raw data will grow. */
427 extra_bss_size =
428 ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss), bss_section),
429 nt_header->OptionalHeader.FileAlignment)
430 - bss_section->SizeOfRawData;
431
432 bss_start_static = my_begbss_static;
433 bss_size_static = my_endbss_static - my_begbss_static;
434 bss_section_static = rva_to_section (PTR_TO_RVA (my_begbss_static), nt_header);
435 if (bss_section_static != rva_to_section (PTR_TO_RVA (my_endbss_static), nt_header))
436 {
437 printf ("Uninitialized static data is not in a single section...bailing\n");
438 exit (1);
439 }
440 /* Compute how much the static .bss section's raw data will grow. */
441 extra_bss_size_static =
442 ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss_static), bss_section_static),
443 nt_header->OptionalHeader.FileAlignment)
444 - bss_section_static->SizeOfRawData;
445
446 /* Combine the bss sections into one if they overlap. */
447 #ifdef _ALPHA_
448 overlap = 1; /* force all bss data to be dumped */
449 #else
450 overlap = 0;
451 #endif
452 if (bss_start < bss_start_static)
453 {
454 if (bss_start_static < bss_start + bss_size)
455 overlap = 1;
456 }
457 else
458 {
459 if (bss_start < bss_start_static + bss_size_static)
460 overlap = 1;
461 }
462 if (overlap)
463 {
464 if (bss_section != bss_section_static)
465 {
466 printf ("BSS data not in a single section...bailing\n");
467 exit (1);
468 }
469 bss_start = min (bss_start, bss_start_static);
470 bss_size = max (my_endbss, my_endbss_static) - bss_start;
471 bss_section_static = 0;
472 extra_bss_size_static = 0;
473 }
474
475 heap_section = rva_to_section (PTR_TO_RVA (get_heap_start ()), nt_header);
476 }
477
478
479 /* The dump routines. */
480
481 void
482 copy_executable_and_dump_data (file_data *p_infile,
483 file_data *p_outfile)
484 {
485 unsigned char *dst, *dst_save;
486 PIMAGE_DOS_HEADER dos_header;
487 PIMAGE_NT_HEADERS nt_header;
488 PIMAGE_NT_HEADERS dst_nt_header;
489 PIMAGE_SECTION_HEADER section;
490 PIMAGE_SECTION_HEADER dst_section;
491 DWORD offset;
492 int i;
493 int be_verbose = GetEnvironmentVariable ("DEBUG_DUMP", NULL, 0) > 0;
494
495 #define COPY_CHUNK(message, src, size, verbose) \
496 do { \
497 unsigned char *s = (void *)(src); \
498 unsigned long count = (size); \
499 if (verbose) \
500 { \
501 printf ("%s\n", (message)); \
502 printf ("\t0x%08x Offset in input file.\n", s - p_infile->file_base); \
503 printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
504 printf ("\t0x%08x Size in bytes.\n", count); \
505 } \
506 memcpy (dst, s, count); \
507 dst += count; \
508 } while (0)
509
510 #define COPY_PROC_CHUNK(message, src, size, verbose) \
511 do { \
512 unsigned char *s = (void *)(src); \
513 unsigned long count = (size); \
514 if (verbose) \
515 { \
516 printf ("%s\n", (message)); \
517 printf ("\t0x%08x Address in process.\n", s); \
518 printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
519 printf ("\t0x%08x Size in bytes.\n", count); \
520 } \
521 memcpy (dst, s, count); \
522 dst += count; \
523 } while (0)
524
525 #define DST_TO_OFFSET() PTR_TO_OFFSET (dst, p_outfile)
526 #define ROUND_UP_DST(align) \
527 (dst = p_outfile->file_base + ROUND_UP (DST_TO_OFFSET (), (align)))
528 #define ROUND_UP_DST_AND_ZERO(align) \
529 do { \
530 unsigned char *newdst = p_outfile->file_base \
531 + ROUND_UP (DST_TO_OFFSET (), (align)); \
532 /* Zero the alignment slop; it may actually initialize real data. */ \
533 memset (dst, 0, newdst - dst); \
534 dst = newdst; \
535 } while (0)
536
537 /* Copy the source image sequentially, ie. section by section after
538 copying the headers and section table, to simplify the process of
539 dumping the raw data for the bss and heap sections.
540
541 Note that dst is updated implicitly by each COPY_CHUNK. */
542
543 dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
544 nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +
545 dos_header->e_lfanew);
546 section = IMAGE_FIRST_SECTION (nt_header);
547
548 dst = (unsigned char *) p_outfile->file_base;
549
550 COPY_CHUNK ("Copying DOS header...", dos_header,
551 (DWORD) nt_header - (DWORD) dos_header, be_verbose);
552 dst_nt_header = (PIMAGE_NT_HEADERS) dst;
553 COPY_CHUNK ("Copying NT header...", nt_header,
554 (DWORD) section - (DWORD) nt_header, be_verbose);
555 dst_section = (PIMAGE_SECTION_HEADER) dst;
556 COPY_CHUNK ("Copying section table...", section,
557 nt_header->FileHeader.NumberOfSections * sizeof (*section),
558 be_verbose);
559
560 /* Align the first section's raw data area, and set the header size
561 field accordingly. */
562 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
563 dst_nt_header->OptionalHeader.SizeOfHeaders = DST_TO_OFFSET ();
564
565 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
566 {
567 char msg[100];
568 /* Windows section names are fixed 8-char strings, only
569 zero-terminated if the name is shorter than 8 characters. */
570 sprintf (msg, "Copying raw data for %.8s...", section->Name);
571
572 dst_save = dst;
573
574 /* Update the file-relative offset for this section's raw data (if
575 it has any) in case things have been relocated; we will update
576 the other offsets below once we know where everything is. */
577 if (dst_section->PointerToRawData)
578 dst_section->PointerToRawData = DST_TO_OFFSET ();
579
580 /* Can always copy the original raw data. */
581 COPY_CHUNK
582 (msg, OFFSET_TO_PTR (section->PointerToRawData, p_infile),
583 section->SizeOfRawData, be_verbose);
584 /* Ensure alignment slop is zeroed. */
585 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
586
587 /* Note that various sections below may be aliases. */
588 if (section == data_section)
589 {
590 dst = dst_save
591 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (data_start), dst_section);
592 COPY_PROC_CHUNK ("Dumping initialized data...",
593 data_start, data_size, be_verbose);
594 dst = dst_save + dst_section->SizeOfRawData;
595 }
596 if (section == bss_section)
597 {
598 /* Dump contents of bss variables, adjusting the section's raw
599 data size as necessary. */
600 dst = dst_save
601 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start), dst_section);
602 COPY_PROC_CHUNK ("Dumping bss data...", bss_start,
603 bss_size, be_verbose);
604 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
605 dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
606 /* Determine new size of raw data area. */
607 dst = max (dst, dst_save + dst_section->SizeOfRawData);
608 dst_section->SizeOfRawData = dst - dst_save;
609 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
610 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
611 }
612 if (section == bss_section_static)
613 {
614 /* Dump contents of static bss variables, adjusting the
615 section's raw data size as necessary. */
616 dst = dst_save
617 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start_static), dst_section);
618 COPY_PROC_CHUNK ("Dumping static bss data...", bss_start_static,
619 bss_size_static, be_verbose);
620 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
621 dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
622 /* Determine new size of raw data area. */
623 dst = max (dst, dst_save + dst_section->SizeOfRawData);
624 dst_section->SizeOfRawData = dst - dst_save;
625 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
626 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
627 }
628 if (section == heap_section)
629 {
630 DWORD heap_start = (DWORD) get_heap_start ();
631 DWORD heap_size = get_committed_heap_size ();
632
633 /* Dump the used portion of the predump heap, adjusting the
634 section's size to the appropriate size. */
635 dst = dst_save
636 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (heap_start), dst_section);
637 COPY_PROC_CHUNK ("Dumping heap...", heap_start, heap_size,
638 be_verbose);
639 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
640 dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
641 /* Determine new size of raw data area. */
642 dst = max (dst, dst_save + dst_section->SizeOfRawData);
643 dst_section->SizeOfRawData = dst - dst_save;
644 /* Reduce the size of the heap section to fit (must be last
645 section). */
646 dst_nt_header->OptionalHeader.SizeOfImage -=
647 dst_section->Misc.VirtualSize
648 - ROUND_UP (dst_section->SizeOfRawData,
649 dst_nt_header->OptionalHeader.SectionAlignment);
650 dst_section->Misc.VirtualSize =
651 ROUND_UP (dst_section->SizeOfRawData,
652 dst_nt_header->OptionalHeader.SectionAlignment);
653 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
654 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
655 }
656
657 /* Align the section's raw data area. */
658 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
659
660 section++;
661 dst_section++;
662 }
663
664 /* Copy remainder of source image. */
665 do
666 section--;
667 while (section->PointerToRawData == 0);
668 offset = ROUND_UP (section->PointerToRawData + section->SizeOfRawData,
669 nt_header->OptionalHeader.FileAlignment);
670 COPY_CHUNK
671 ("Copying remainder of executable...",
672 OFFSET_TO_PTR (offset, p_infile),
673 p_infile->size - offset, be_verbose);
674
675 /* Final size for new image. */
676 p_outfile->size = DST_TO_OFFSET ();
677
678 /* Now patch up remaining file-relative offsets. */
679 section = IMAGE_FIRST_SECTION (nt_header);
680 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
681
682 #define ADJUST_OFFSET(var) \
683 do { \
684 if ((var) != 0) \
685 (var) = relocate_offset ((var), nt_header, dst_nt_header); \
686 } while (0)
687
688 dst_nt_header->OptionalHeader.SizeOfInitializedData = 0;
689 dst_nt_header->OptionalHeader.SizeOfUninitializedData = 0;
690 for (i = 0; i < dst_nt_header->FileHeader.NumberOfSections; i++)
691 {
692 /* Recompute data sizes for completeness. */
693 if (dst_section[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
694 dst_nt_header->OptionalHeader.SizeOfInitializedData +=
695 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
696 else if (dst_section[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
697 dst_nt_header->OptionalHeader.SizeOfUninitializedData +=
698 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
699
700 ADJUST_OFFSET (dst_section[i].PointerToLinenumbers);
701 }
702
703 ADJUST_OFFSET (dst_nt_header->FileHeader.PointerToSymbolTable);
704
705 /* Update offsets in debug directory entries. */
706 {
707 IMAGE_DATA_DIRECTORY debug_dir =
708 dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
709 PIMAGE_DEBUG_DIRECTORY debug_entry;
710
711 section = rva_to_section (debug_dir.VirtualAddress, dst_nt_header);
712 if (section)
713 {
714 debug_entry = (PIMAGE_DEBUG_DIRECTORY)
715 (RVA_TO_OFFSET (debug_dir.VirtualAddress, section) + p_outfile->file_base);
716 debug_dir.Size /= sizeof (IMAGE_DEBUG_DIRECTORY);
717
718 for (i = 0; i < debug_dir.Size; i++, debug_entry++)
719 ADJUST_OFFSET (debug_entry->PointerToRawData);
720 }
721 }
722 }
723
724
725 /* Dump out .data and .bss sections into a new executable. */
726 int
727 unexec (const char *new_name, const char *old_name)
728 {
729 file_data in_file, out_file;
730 char out_filename[MAX_PATH], in_filename[MAX_PATH];
731 unsigned long size;
732 char *p;
733 char *q;
734
735 /* Ignore old_name, and get our actual location from the OS. */
736 if (!GetModuleFileName (NULL, in_filename, MAX_PATH))
737 abort ();
738 dostounix_filename (in_filename);
739 strcpy (out_filename, in_filename);
740
741 /* Change the base of the output filename to match the requested name. */
742 if ((p = strrchr (out_filename, '/')) == NULL)
743 abort ();
744 /* The filenames have already been expanded, and will be in Unix
745 format, so it is safe to expect an absolute name. */
746 if ((q = strrchr (new_name, '/')) == NULL)
747 abort ();
748 strcpy (p, q);
749
750 /* Make sure that the output filename has the ".exe" extension...patch
751 it up if not. */
752 p = out_filename + strlen (out_filename) - 4;
753 if (strcmp (p, ".exe"))
754 strcat (out_filename, ".exe");
755
756 printf ("Dumping from %s\n", in_filename);
757 printf (" to %s\n", out_filename);
758
759 /* We need to round off our heap to NT's page size. */
760 round_heap (get_page_size ());
761
762 /* Open the undumped executable file. */
763 if (!open_input_file (&in_file, in_filename))
764 {
765 printf ("Failed to open %s (%d)...bailing.\n",
766 in_filename, GetLastError ());
767 exit (1);
768 }
769
770 /* Get the interesting section info, like start and size of .bss... */
771 get_section_info (&in_file);
772
773 /* The size of the dumped executable is the size of the original
774 executable plus the size of the heap and the size of the .bss section. */
775 size = in_file.size +
776 get_committed_heap_size () +
777 extra_bss_size +
778 extra_bss_size_static;
779 if (!open_output_file (&out_file, out_filename, size))
780 {
781 printf ("Failed to open %s (%d)...bailing.\n",
782 out_filename, GetLastError ());
783 exit (1);
784 }
785
786 /* Set the flag (before dumping). */
787 using_dynamic_heap = TRUE;
788
789 copy_executable_and_dump_data (&in_file, &out_file);
790
791 /* Patch up header fields; profiler is picky about this. */
792 {
793 PIMAGE_DOS_HEADER dos_header;
794 PIMAGE_NT_HEADERS nt_header;
795 HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
796 DWORD headersum;
797 DWORD checksum;
798
799 dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
800 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
801
802 nt_header->OptionalHeader.CheckSum = 0;
803 // nt_header->FileHeader.TimeDateStamp = time (NULL);
804 // dos_header->e_cp = size / 512;
805 // nt_header->OptionalHeader.SizeOfImage = size;
806
807 pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
808 if (pfnCheckSumMappedFile)
809 {
810 // nt_header->FileHeader.TimeDateStamp = time (NULL);
811 pfnCheckSumMappedFile (out_file.file_base,
812 out_file.size,
813 &headersum,
814 &checksum);
815 nt_header->OptionalHeader.CheckSum = checksum;
816 }
817 FreeLibrary (hImagehelp);
818 }
819
820 close_file_data (&in_file);
821 close_file_data (&out_file);
822
823 return 0;
824 }
825
826 /* eof */
827