aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrew Innes1999-01-17 19:21:24 +0000
committerAndrew Innes1999-01-17 19:21:24 +0000
commit5b79dba5b941740286727d2d24091bdec94e2f6f (patch)
tree46b0e456fc90b9a84819fc4acea514e26171224b /src
parent3bc2366f3c270b81e1845f5d4218d5acbdeec916 (diff)
downloademacs-5b79dba5b941740286727d2d24091bdec94e2f6f.tar.gz
emacs-5b79dba5b941740286727d2d24091bdec94e2f6f.zip
Major rewrite to support cleaner method of dumping; a
static "bss" section is used for heap space during preload, and bss data is now written to the proper section area when dumping. (need_to_recreate_heap): Renamed to using_dynamic_heap. (heap_index_in_executable): Obsolete variable removed. (data_section): New variable. (data_start_va): Renamed to data_start. (data_start_file): Obsolete variable removed. (bss_section): (extra_bss_size): (bss_section_static): (bss_start_static): (bss_size_static): (extra_bss_size_static): (heap_section): New variables. (_start): Remove code based on old unexec method. Call init_heap to initialize sbrk heap. (close_file_data): Update size of file when closing, so that unexec doesn't have to work out exact size in advance. (get_bss_info_from_map_file): (get_section_size): Obsolete functions removed. (rva_to_section): Fix minor bug, and add a work-around for a bug in very old linkers. (offset_to_section): (relocate_offset): New functions. (OFFSET_TO_RVA): (RVA_TO_OFFSET): (RVA_TO_SECTION_OFFSET): (PTR_TO_RVA): (PTR_TO_OFFSET): (OFFSET_TO_PTR): New macros. (get_section_info): Modify to support new unexec method; determines address ranges in process that need dumping, and COFF sections where data will be dumped. Allows for static and global bss data to be in separate ranges. No longer relies on knowledge of section names. (copy_executable_and_dump_data_section): Renamed copy_executable_and_dump_data. Completely rewritten to copy executable section by section, so that raw data areas can be expanded to hold dumped data as necessary. Allows for bss data to be in same section as initialized data. Reduces size of static heap section to that used during preload. (dump_bss_and_heap): (w32_fatal_reload_error): (read_in_bss): (map_in_heap): Obsolete functions removed. (unexec): Rounds off preload heap to nearest page rather than virtual allocation unit. Modified to match other changes.
Diffstat (limited to 'src')
-rw-r--r--src/unexw32.c908
1 files changed, 470 insertions, 438 deletions
diff --git a/src/unexw32.c b/src/unexw32.c
index f7314e79207..4cdffac287d 100644
--- a/src/unexw32.c
+++ b/src/unexw32.c
@@ -55,27 +55,33 @@ extern char *my_endbss_static;
55#define max(x, y) (((x) > (y)) ? (x) : (y)) 55#define max(x, y) (((x) > (y)) ? (x) : (y))
56 56
57/* Basically, our "initialized" flag. */ 57/* Basically, our "initialized" flag. */
58BOOL need_to_recreate_heap = FALSE; 58BOOL using_dynamic_heap = FALSE;
59
60/* So we can find our heap in the file to recreate it. */
61unsigned long heap_index_in_executable = 0;
62 59
63int open_input_file (file_data *p_file, char *name); 60int open_input_file (file_data *p_file, char *name);
64int open_output_file (file_data *p_file, char *name, unsigned long size); 61int open_output_file (file_data *p_file, char *name, unsigned long size);
65void close_file_data (file_data *p_file); 62void close_file_data (file_data *p_file);
66 63
67void get_section_info (file_data *p_file); 64void get_section_info (file_data *p_file);
68void copy_executable_and_dump_data_section (file_data *, file_data *); 65void copy_executable_and_dump_data (file_data *, file_data *);
69void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile); 66void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile);
70 67
71/* Cached info about the .data section in the executable. */ 68/* Cached info about the .data section in the executable. */
72PUCHAR data_start_va = 0; 69PIMAGE_SECTION_HEADER data_section;
73DWORD data_start_file = 0; 70PUCHAR data_start = 0;
74DWORD data_size = 0; 71DWORD data_size = 0;
75 72
76/* Cached info about the .bss section in the executable. */ 73/* Cached info about the .bss section in the executable. */
74PIMAGE_SECTION_HEADER bss_section;
77PUCHAR bss_start = 0; 75PUCHAR bss_start = 0;
78DWORD bss_size = 0; 76DWORD bss_size = 0;
77DWORD extra_bss_size = 0;
78/* bss data that is static might be discontiguous from non-static. */
79PIMAGE_SECTION_HEADER bss_section_static;
80PUCHAR bss_start_static = 0;
81DWORD bss_size_static = 0;
82DWORD extra_bss_size_static = 0;
83
84PIMAGE_SECTION_HEADER heap_section;
79 85
80#ifdef HAVE_NTGUI 86#ifdef HAVE_NTGUI
81HINSTANCE hinst = NULL; 87HINSTANCE hinst = NULL;
@@ -103,49 +109,8 @@ _start (void)
103 /* Cache system info, e.g., the NT page size. */ 109 /* Cache system info, e.g., the NT page size. */
104 cache_system_info (); 110 cache_system_info ();
105 111
106 /* If we're a dumped version of emacs then we need to recreate 112 /* Grab our malloc arena space now, before CRT starts up. */
107 our heap and play tricks with our .bss section. Do this before 113 init_heap ();
108 start up. (WARNING: Do not put any code before this section
109 that relies upon malloc () and runs in the dumped version. It
110 won't work.) */
111 if (need_to_recreate_heap)
112 {
113 char executable_path[MAX_PATH];
114
115 if (GetModuleFileName (NULL, executable_path, MAX_PATH) == 0)
116 {
117 printf ("Failed to find path for executable.\n");
118 exit (1);
119 }
120
121#if 1
122 /* To allow profiling, make sure executable_path names the .exe
123 file, not the ._xe file created by the profiler which contains
124 extra code that makes the stored exe offsets incorrect. (This
125 will not be necessary when unexec properly extends the .bss (or
126 .data as appropriate) section to include the dumped bss data,
127 and dumps the heap into a proper section of its own.) */
128 {
129 char * p = strrchr (executable_path, '.');
130 if (p && p[1] == '_')
131 p[1] = 'e';
132 }
133
134 /* Using HiProf profiler, exe name is different still. */
135 {
136 char * p = strrchr (executable_path, '\\');
137 strcpy (p, "\\emacs.exe");
138 }
139#endif
140
141 recreate_heap (executable_path);
142 need_to_recreate_heap = FALSE;
143 }
144 else
145 {
146 /* Grab our malloc arena space now, before CRT starts up. */
147 sbrk (0);
148 }
149 114
150 /* The default behavior is to treat files as binary and patch up 115 /* The default behavior is to treat files as binary and patch up
151 text files appropriately, in accordance with the MSDOS code. */ 116 text files appropriately, in accordance with the MSDOS code. */
@@ -170,100 +135,9 @@ _start (void)
170 mainCRTStartup (); 135 mainCRTStartup ();
171} 136}
172 137
173/* Dump out .data and .bss sections into a new executable. */
174void
175unexec (char *new_name, char *old_name, void *start_data, void *start_bss,
176 void *entry_address)
177{
178 file_data in_file, out_file;
179 char out_filename[MAX_PATH], in_filename[MAX_PATH];
180 unsigned long size;
181 char *ptr;
182
183 /* Make sure that the input and output filenames have the
184 ".exe" extension...patch them up if they don't. */
185 strcpy (in_filename, old_name);
186 ptr = in_filename + strlen (in_filename) - 4;
187 if (strcmp (ptr, ".exe"))
188 strcat (in_filename, ".exe");
189
190 strcpy (out_filename, new_name);
191 ptr = out_filename + strlen (out_filename) - 4;
192 if (strcmp (ptr, ".exe"))
193 strcat (out_filename, ".exe");
194
195 printf ("Dumping from %s\n", in_filename);
196 printf (" to %s\n", out_filename);
197
198 /* We need to round off our heap to NT's allocation unit (64KB). */
199 round_heap (get_allocation_unit ());
200
201 /* Open the undumped executable file. */
202 if (!open_input_file (&in_file, in_filename))
203 {
204 printf ("Failed to open %s (%d)...bailing.\n",
205 in_filename, GetLastError ());
206 exit (1);
207 }
208
209 /* Get the interesting section info, like start and size of .bss... */
210 get_section_info (&in_file);
211
212 /* The size of the dumped executable is the size of the original
213 executable plus the size of the heap and the size of the .bss section. */
214 heap_index_in_executable = (unsigned long)
215 round_to_next ((unsigned char *) in_file.size, get_allocation_unit ());
216 size = heap_index_in_executable + get_committed_heap_size () + bss_size;
217 if (!open_output_file (&out_file, out_filename, size))
218 {
219 printf ("Failed to open %s (%d)...bailing.\n",
220 out_filename, GetLastError ());
221 exit (1);
222 }
223
224 /* Set the flag (before dumping). */
225 need_to_recreate_heap = TRUE;
226
227 copy_executable_and_dump_data_section (&in_file, &out_file);
228 dump_bss_and_heap (&in_file, &out_file);
229
230 /* Patch up header fields; profiler is picky about this. */
231 {
232 PIMAGE_DOS_HEADER dos_header;
233 PIMAGE_NT_HEADERS nt_header;
234 HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
235 DWORD headersum;
236 DWORD checksum;
237
238 dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
239 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
240
241 nt_header->OptionalHeader.CheckSum = 0;
242// nt_header->FileHeader.TimeDateStamp = time (NULL);
243// dos_header->e_cp = size / 512;
244// nt_header->OptionalHeader.SizeOfImage = size;
245
246 pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
247 if (pfnCheckSumMappedFile)
248 {
249// nt_header->FileHeader.TimeDateStamp = time (NULL);
250 pfnCheckSumMappedFile (out_file.file_base,
251 out_file.size,
252 &headersum,
253 &checksum);
254 nt_header->OptionalHeader.CheckSum = checksum;
255 }
256 FreeLibrary (hImagehelp);
257 }
258
259 close_file_data (&in_file);
260 close_file_data (&out_file);
261}
262
263 138
264/* File handling. */ 139/* File handling. */
265 140
266
267int 141int
268open_input_file (file_data *p_file, char *filename) 142open_input_file (file_data *p_file, char *filename)
269{ 143{
@@ -330,64 +204,17 @@ open_output_file (file_data *p_file, char *filename, unsigned long size)
330void 204void
331close_file_data (file_data *p_file) 205close_file_data (file_data *p_file)
332{ 206{
333 UnmapViewOfFile (p_file->file_base); 207 UnmapViewOfFile (p_file->file_base);
334 CloseHandle (p_file->file_mapping); 208 CloseHandle (p_file->file_mapping);
335 CloseHandle (p_file->file); 209 /* For the case of output files, set final size. */
210 SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN);
211 SetEndOfFile (p_file->file);
212 CloseHandle (p_file->file);
336} 213}
337 214
338 215
339/* Routines to manipulate NT executable file sections. */ 216/* Routines to manipulate NT executable file sections. */
340 217
341#ifdef SEPARATE_BSS_SECTION
342static void
343get_bss_info_from_map_file (file_data *p_infile, PUCHAR *p_bss_start,
344 DWORD *p_bss_size)
345{
346 int n, start, len;
347 char map_filename[MAX_PATH];
348 char buffer[256];
349 FILE *map;
350
351 /* Overwrite the .exe extension on the executable file name with
352 the .map extension. */
353 strcpy (map_filename, p_infile->name);
354 n = strlen (map_filename) - 3;
355 strcpy (&map_filename[n], "map");
356
357 map = fopen (map_filename, "r");
358 if (!map)
359 {
360 printf ("Failed to open map file %s, error %d...bailing out.\n",
361 map_filename, GetLastError ());
362 exit (-1);
363 }
364
365 while (fgets (buffer, sizeof (buffer), map))
366 {
367 if (!(strstr (buffer, ".bss") && strstr (buffer, "DATA")))
368 continue;
369 n = sscanf (buffer, " %*d:%x %x", &start, &len);
370 if (n != 2)
371 {
372 printf ("Failed to scan the .bss section line:\n%s", buffer);
373 exit (-1);
374 }
375 break;
376 }
377 *p_bss_start = (PUCHAR) start;
378 *p_bss_size = (DWORD) len;
379}
380#endif
381
382unsigned long
383get_section_size (PIMAGE_SECTION_HEADER p_section)
384{
385 /* The true section size, before rounding. Some linkers swap the
386 meaning of these two values. */
387 return min (p_section->SizeOfRawData,
388 p_section->Misc.VirtualSize);
389}
390
391/* Return pointer to section header for named section. */ 218/* Return pointer to section header for named section. */
392IMAGE_SECTION_HEADER * 219IMAGE_SECTION_HEADER *
393find_section (char * name, IMAGE_NT_HEADERS * nt_header) 220find_section (char * name, IMAGE_NT_HEADERS * nt_header)
@@ -418,14 +245,97 @@ rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
418 245
419 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) 246 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
420 { 247 {
248 /* Some linkers (eg. the NT SDK linker I believe) swapped the
249 meaning of these two values - or rather, they ignored
250 VirtualSize entirely and always set it to zero. This affects
251 some very old exes (eg. gzip dated Dec 1993). Since
252 w32_executable_type relies on this function to work reliably,
253 we need to cope with this. */
254 DWORD real_size = max (section->SizeOfRawData,
255 section->Misc.VirtualSize);
421 if (rva >= section->VirtualAddress 256 if (rva >= section->VirtualAddress
422 && rva < section->VirtualAddress + section->SizeOfRawData) 257 && rva < section->VirtualAddress + real_size)
258 return section;
259 section++;
260 }
261 return NULL;
262}
263
264/* Return pointer to section header for section containing the given
265 offset in its raw data area. */
266IMAGE_SECTION_HEADER *
267offset_to_section (DWORD offset, IMAGE_NT_HEADERS * nt_header)
268{
269 PIMAGE_SECTION_HEADER section;
270 int i;
271
272 section = IMAGE_FIRST_SECTION (nt_header);
273
274 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
275 {
276 if (offset >= section->PointerToRawData
277 && offset < section->PointerToRawData + section->SizeOfRawData)
423 return section; 278 return section;
424 section++; 279 section++;
425 } 280 }
426 return NULL; 281 return NULL;
427} 282}
428 283
284/* Return offset to an object in dst, given offset in src. We assume
285 there is at least one section in both src and dst images, and that
286 the some sections may have been added to dst (after sections in src). */
287static DWORD
288relocate_offset (DWORD offset,
289 IMAGE_NT_HEADERS * src_nt_header,
290 IMAGE_NT_HEADERS * dst_nt_header)
291{
292 PIMAGE_SECTION_HEADER src_section = IMAGE_FIRST_SECTION (src_nt_header);
293 PIMAGE_SECTION_HEADER dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
294 int i = 0;
295
296 while (offset >= src_section->PointerToRawData)
297 {
298 if (offset < src_section->PointerToRawData + src_section->SizeOfRawData)
299 break;
300 i++;
301 if (i == src_nt_header->FileHeader.NumberOfSections)
302 {
303 /* Handle offsets after the last section. */
304 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
305 dst_section += dst_nt_header->FileHeader.NumberOfSections - 1;
306 while (dst_section->PointerToRawData == 0)
307 dst_section--;
308 while (src_section->PointerToRawData == 0)
309 src_section--;
310 return offset
311 + (dst_section->PointerToRawData + dst_section->SizeOfRawData)
312 - (src_section->PointerToRawData + src_section->SizeOfRawData);
313 }
314 src_section++;
315 dst_section++;
316 }
317 return offset +
318 (dst_section->PointerToRawData - src_section->PointerToRawData);
319}
320
321#define OFFSET_TO_RVA(offset, section) \
322 (section->VirtualAddress + ((DWORD)(offset) - section->PointerToRawData))
323
324#define RVA_TO_OFFSET(rva, section) \
325 (section->PointerToRawData + ((DWORD)(rva) - section->VirtualAddress))
326
327#define RVA_TO_SECTION_OFFSET(rva, section) \
328 ((DWORD)(rva) - section->VirtualAddress)
329
330/* Convert address in executing image to RVA. */
331#define PTR_TO_RVA(ptr) ((DWORD)(ptr) - (DWORD) GetModuleHandle (NULL))
332
333#define PTR_TO_OFFSET(ptr, pfile_data) \
334 ((char *)(ptr) - (pfile_data)->file_base)
335
336#define OFFSET_TO_PTR(offset, pfile_data) \
337 ((pfile_data)->file_base + (DWORD)(offset))
338
429 339
430/* Flip through the executable and cache the info necessary for dumping. */ 340/* Flip through the executable and cache the info necessary for dumping. */
431static void 341static void
@@ -433,9 +343,8 @@ get_section_info (file_data *p_infile)
433{ 343{
434 PIMAGE_DOS_HEADER dos_header; 344 PIMAGE_DOS_HEADER dos_header;
435 PIMAGE_NT_HEADERS nt_header; 345 PIMAGE_NT_HEADERS nt_header;
436 PIMAGE_SECTION_HEADER section, data_section; 346 PIMAGE_SECTION_HEADER section;
437 unsigned char *ptr; 347 int overlap;
438 int i;
439 348
440 dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base; 349 dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
441 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) 350 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
@@ -457,281 +366,404 @@ get_section_info (file_data *p_infile)
457 { 366 {
458 printf ("Invalid IMAGE_NT_SIGNATURE 0x%x in %s...bailing.\n", 367 printf ("Invalid IMAGE_NT_SIGNATURE 0x%x in %s...bailing.\n",
459 nt_header->Signature, p_infile->name); 368 nt_header->Signature, p_infile->name);
369 exit (1);
460 } 370 }
461 371
462 /* Flip through the sections for .data and .bss ... */ 372 /* Locate the ".data" and ".bss" sections for Emacs. (Note that the
463 section = (PIMAGE_SECTION_HEADER) IMAGE_FIRST_SECTION (nt_header); 373 actual section names are probably different from these, and might
464 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) 374 actually be the same section.)
375
376 We do this as follows: first we determine the virtual address
377 ranges in this process for the data and bss variables that we wish
378 to preserve. Then we map these VAs to the section entries in the
379 source image. Finally, we determine the new size of the raw data
380 area for the bss section, so we can make the new image the correct
381 size. */
382
383 data_start = my_begdata;
384 data_size = my_edata - my_begdata;
385 data_section = rva_to_section (PTR_TO_RVA (my_begdata), nt_header);
386 if (data_section != rva_to_section (PTR_TO_RVA (my_edata), nt_header))
465 { 387 {
466#ifdef SEPARATE_BSS_SECTION 388 printf ("Initialized data is not in a single section...bailing\n");
467 if (!strcmp (section->Name, ".bss")) 389 exit (1);
390 }
391
392 /* As noted in lastfile.c, the Alpha (but not the Intel) MSVC linker
393 globally segregates all static and public bss data (ie. across all
394 linked modules, not just per module), so we must take both static
395 and public bss areas into account to determine the true extent of
396 the bss area used by Emacs.
397
398 To be strictly correct, we dump the static and public bss areas
399 used by Emacs separately if non-overlapping (since otherwise we are
400 dumping bss data belonging to system libraries, eg. the static bss
401 system data on the Alpha). */
402
403 bss_start = my_begbss;
404 bss_size = my_endbss - my_begbss;
405 bss_section = rva_to_section (PTR_TO_RVA (my_begbss), nt_header);
406 if (bss_section != rva_to_section (PTR_TO_RVA (my_endbss), nt_header))
407 {
408 printf ("Uninitialized data is not in a single section...bailing\n");
409 exit (1);
410 }
411 /* Compute how much the .bss section's raw data will grow. */
412 extra_bss_size =
413 ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss), bss_section),
414 nt_header->OptionalHeader.FileAlignment)
415 - bss_section->SizeOfRawData;
416
417 bss_start_static = my_begbss_static;
418 bss_size_static = my_endbss_static - my_begbss_static;
419 bss_section_static = rva_to_section (PTR_TO_RVA (my_begbss_static), nt_header);
420 if (bss_section_static != rva_to_section (PTR_TO_RVA (my_endbss_static), nt_header))
421 {
422 printf ("Uninitialized static data is not in a single section...bailing\n");
423 exit (1);
424 }
425 /* Compute how much the static .bss section's raw data will grow. */
426 extra_bss_size_static =
427 ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss_static), bss_section_static),
428 nt_header->OptionalHeader.FileAlignment)
429 - bss_section_static->SizeOfRawData;
430
431 /* Combine the bss sections into one if they overlap. */
432 overlap = 0;
433 if (bss_start < bss_start_static)
434 {
435 if (bss_start_static < bss_start + bss_size)
436 overlap = 1;
437 }
438 else
439 {
440 if (bss_start < bss_start_static + bss_size_static)
441 overlap = 1;
442 }
443 if (overlap)
444 {
445 if (bss_section != bss_section_static)
468 { 446 {
469 /* The .bss section. */ 447 printf ("BSS data not in a single section...bailing\n");
470 ptr = (char *) nt_header->OptionalHeader.ImageBase + 448 exit (1);
471 section->VirtualAddress;
472 bss_start = ptr;
473 bss_size = get_section_size (section);
474 } 449 }
475#endif 450 bss_start = min (bss_start, bss_start_static);
476#if 0 451 bss_size = max (my_endbss, my_endbss_static) - bss_start;
477 if (!strcmp (section->Name, ".data")) 452 bss_section_static = 0;
453 extra_bss_size_static = 0;
454 }
455
456 heap_section = rva_to_section (PTR_TO_RVA (get_heap_start ()), nt_header);
457}
458
459
460/* The dump routines. */
461
462static void
463copy_executable_and_dump_data (file_data *p_infile,
464 file_data *p_outfile)
465{
466 unsigned char *dst, *dst_save;
467 PIMAGE_DOS_HEADER dos_header;
468 PIMAGE_NT_HEADERS nt_header;
469 PIMAGE_NT_HEADERS dst_nt_header;
470 PIMAGE_SECTION_HEADER section;
471 PIMAGE_SECTION_HEADER dst_section;
472 DWORD offset;
473 int i;
474
475#define COPY_CHUNK(message, src, size) \
476 do { \
477 unsigned char *s = (void *)(src); \
478 unsigned long count = (size); \
479 printf ("%s\n", (message)); \
480 printf ("\t0x%08x Offset in input file.\n", s - p_infile->file_base); \
481 printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
482 printf ("\t0x%08x Size in bytes.\n", count); \
483 memcpy (dst, s, count); \
484 dst += count; \
485 } while (0)
486
487#define COPY_PROC_CHUNK(message, src, size) \
488 do { \
489 unsigned char *s = (void *)(src); \
490 unsigned long count = (size); \
491 printf ("%s\n", (message)); \
492 printf ("\t0x%08x Address in process.\n", s); \
493 printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
494 printf ("\t0x%08x Size in bytes.\n", count); \
495 memcpy (dst, s, count); \
496 dst += count; \
497 } while (0)
498
499#define DST_TO_OFFSET() PTR_TO_OFFSET (dst, p_outfile)
500#define ROUND_UP_DST(align) \
501 (dst = p_outfile->file_base + ROUND_UP (DST_TO_OFFSET (), (align)))
502
503 /* Copy the source image sequentially, ie. section by section after
504 copying the headers and section table, to simplify the process of
505 dumping the raw data for the bss and heap sections.
506
507 Note that dst is updated implicitly by each COPY_CHUNK. */
508
509 dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
510 nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +
511 dos_header->e_lfanew);
512 section = IMAGE_FIRST_SECTION (nt_header);
513
514 dst = (unsigned char *) p_outfile->file_base;
515
516 COPY_CHUNK ("Copying DOS header...", dos_header,
517 (DWORD) nt_header - (DWORD) dos_header);
518 dst_nt_header = (PIMAGE_NT_HEADERS) dst;
519 COPY_CHUNK ("Copying NT header...", nt_header,
520 (DWORD) section - (DWORD) nt_header);
521 dst_section = (PIMAGE_SECTION_HEADER) dst;
522 COPY_CHUNK ("Copying section table...", section,
523 nt_header->FileHeader.NumberOfSections * sizeof (*section));
524
525 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
526 {
527 char msg[100];
528 sprintf (msg, "Copying raw data for %s...", section->Name);
529
530 /* Align the section's raw data area. */
531 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
532 dst_save = dst;
533
534 /* Update the file-relative offset for this section's raw data (if
535 it has any) in case things have been relocated; we will update
536 the other offsets below once we know where everything is. */
537 if (dst_section->PointerToRawData)
538 dst_section->PointerToRawData = DST_TO_OFFSET ();
539
540 /* Can always copy the original raw data. */
541 COPY_CHUNK
542 (msg, OFFSET_TO_PTR (section->PointerToRawData, p_infile),
543 section->SizeOfRawData);
544
545 /* Note that various sections below may be aliases. */
546 if (section == data_section)
478 { 547 {
479 /* From lastfile.c */ 548 dst = dst_save
480 extern char my_edata[]; 549 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (data_start), dst_section);
481 550 COPY_PROC_CHUNK ("Dumping initialized data...", data_start, data_size);
482 /* The .data section. */ 551 dst = dst_save + dst_section->SizeOfRawData;
483 data_section = section;
484 ptr = (char *) nt_header->OptionalHeader.ImageBase +
485 section->VirtualAddress;
486 data_start_va = ptr;
487 data_start_file = section->PointerToRawData;
488
489 /* We want to only write Emacs data back to the executable,
490 not any of the library data (if library data is included,
491 then a dumped Emacs won't run on system versions other
492 than the one Emacs was dumped on). */
493 data_size = my_edata - data_start_va;
494 } 552 }
495#else 553 if (section == bss_section)
496 if (!strcmp (section->Name, "EMDATA"))
497 { 554 {
498 /* The Emacs initialized data section. */ 555 /* Dump contents of bss variables, adjusting the section's raw
499 data_section = section; 556 data size as necessary. */
500 ptr = (char *) nt_header->OptionalHeader.ImageBase + 557 dst = dst_save
501 section->VirtualAddress; 558 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start), dst_section);
502 data_start_va = ptr; 559 COPY_PROC_CHUNK ("Dumping bss data...", bss_start, bss_size);
503 data_start_file = section->PointerToRawData; 560 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
504 561 dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
505 /* Write back the full section. */ 562 /* Determine new size of raw data area. */
506 data_size = get_section_size (section); 563 dst = max (dst, dst_save + dst_section->SizeOfRawData);
564 dst_section->SizeOfRawData = dst - dst_save;
565 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
566 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
507 } 567 }
508#endif 568 if (section == bss_section_static)
569 {
570 /* Dump contents of static bss variables, adjusting the
571 section's raw data size as necessary. */
572 dst = dst_save
573 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start_static), dst_section);
574 COPY_PROC_CHUNK ("Dumping static bss data...", bss_start_static, bss_size_static);
575 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
576 dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
577 /* Determine new size of raw data area. */
578 dst = max (dst, dst_save + dst_section->SizeOfRawData);
579 dst_section->SizeOfRawData = dst - dst_save;
580 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
581 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
582 }
583 if (section == heap_section)
584 {
585 DWORD heap_start = get_heap_start ();
586 DWORD heap_size = get_committed_heap_size ();
587
588 /* Dump the used portion of the predump heap, adjusting the
589 section's size to the appropriate size. */
590 dst = dst_save
591 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (heap_start), dst_section);
592 COPY_PROC_CHUNK ("Dumping heap...", heap_start, heap_size);
593 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
594 dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
595 /* Determine new size of raw data area. */
596 dst = max (dst, dst_save + dst_section->SizeOfRawData);
597 dst_section->SizeOfRawData = dst - dst_save;
598 /* Reduce the size of the heap section to fit (must be last
599 section). */
600 dst_nt_header->OptionalHeader.SizeOfImage -=
601 dst_section->Misc.VirtualSize
602 - ROUND_UP (dst_section->SizeOfRawData,
603 dst_nt_header->OptionalHeader.SectionAlignment);
604 dst_section->Misc.VirtualSize =
605 ROUND_UP (dst_section->SizeOfRawData,
606 dst_nt_header->OptionalHeader.SectionAlignment);
607 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
608 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
609 }
610
509 section++; 611 section++;
612 dst_section++;
510 } 613 }
511 614
512#ifdef SEPARATE_BSS_SECTION 615 /* Pad out the final section raw data area. */
513 if (bss_start == UNINIT_PTR && bss_size == UNINIT_LONG) 616 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
617
618 /* Copy remainder of source image. */
619 do
620 section--;
621 while (section->PointerToRawData == 0);
622 offset = ROUND_UP (section->PointerToRawData + section->SizeOfRawData,
623 nt_header->OptionalHeader.FileAlignment);
624 COPY_CHUNK
625 ("Copying remainder of executable...",
626 OFFSET_TO_PTR (offset, p_infile),
627 p_infile->size - offset);
628
629 /* Final size for new image. */
630 p_outfile->size = DST_TO_OFFSET ();
631
632 /* Now patch up remaining file-relative offsets. */
633 section = IMAGE_FIRST_SECTION (nt_header);
634 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
635
636#define ADJUST_OFFSET(var) \
637 do { \
638 if ((var) != 0) \
639 (var) = relocate_offset ((var), nt_header, dst_nt_header); \
640 } while (0)
641
642 dst_nt_header->OptionalHeader.SizeOfInitializedData = 0;
643 dst_nt_header->OptionalHeader.SizeOfUninitializedData = 0;
644 for (i = 0; i < dst_nt_header->FileHeader.NumberOfSections; i++)
514 { 645 {
515 /* Starting with MSVC 4.0, the .bss section has been eliminated 646 /* Recompute data sizes for completeness. */
516 and appended virtually to the end of the .data section. Our 647 if (dst_section[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
517 only hint about where the .bss section starts in the address 648 dst_nt_header->OptionalHeader.SizeOfInitializedData +=
518 comes from the SizeOfRawData field in the .data section 649 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
519 header. Unfortunately, this field is only approximate, as it 650 else if (dst_section[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
520 is a rounded number and is typically rounded just beyond the 651 dst_nt_header->OptionalHeader.SizeOfUninitializedData +=
521 start of the .bss section. To find the start and size of the 652 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
522 .bss section exactly, we have to peek into the map file. */ 653
523 get_bss_info_from_map_file (p_infile, &ptr, &bss_size); 654 ADJUST_OFFSET (dst_section[i].PointerToLinenumbers);
524 bss_start = ptr + nt_header->OptionalHeader.ImageBase
525 + data_section->VirtualAddress;
526 } 655 }
527#else
528/* As noted in lastfile.c, the Alpha (but not the Intel) MSVC linker
529 globally segregates all static and public bss data (ie. across all
530 linked modules, not just per module), so we must take both static and
531 public bss areas into account to determine the true extent of the bss
532 area used by Emacs.
533
534 To be strictly correct, we should dump the static and public bss
535 areas used by Emacs separately if non-overlapping (since otherwise we
536 are dumping bss data belonging to system libraries, eg. the static
537 bss system data on the Alpha). However, in practice this doesn't
538 seem to matter, since presumably the system libraries always
539 reinitialize their bss variables. */
540 bss_start = min (my_begbss, my_begbss_static);
541 bss_size = max (my_endbss, my_endbss_static) - bss_start;
542#endif
543}
544 656
657 ADJUST_OFFSET (dst_nt_header->FileHeader.PointerToSymbolTable);
545 658
546/* The dump routines. */ 659 /* Update offsets in debug directory entries. */
660 {
661 IMAGE_DATA_DIRECTORY debug_dir =
662 dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
663 PIMAGE_DEBUG_DIRECTORY debug_entry;
547 664
548static void 665 section = rva_to_section (debug_dir.VirtualAddress, dst_nt_header);
549copy_executable_and_dump_data_section (file_data *p_infile, 666 if (section)
550 file_data *p_outfile) 667 {
551{ 668 debug_entry = (PIMAGE_DEBUG_DIRECTORY)
552 unsigned char *data_file, *data_va; 669 (RVA_TO_OFFSET (debug_dir.VirtualAddress, section) + p_outfile->file_base);
553 unsigned long size, index; 670 debug_dir.Size /= sizeof (IMAGE_DEBUG_DIRECTORY);
554
555 /* Get a pointer to where the raw data should go in the executable file. */
556 data_file = (char *) p_outfile->file_base + data_start_file;
557
558 /* Get a pointer to the raw data in our address space. */
559 data_va = data_start_va;
560
561 size = (DWORD) data_file - (DWORD) p_outfile->file_base;
562 printf ("Copying executable up to data section...\n");
563 printf ("\t0x%08x Offset in input file.\n", 0);
564 printf ("\t0x%08x Offset in output file.\n", 0);
565 printf ("\t0x%08x Size in bytes.\n", size);
566 memcpy (p_outfile->file_base, p_infile->file_base, size);
567
568 size = data_size;
569 printf ("Dumping .data section...\n");
570 printf ("\t0x%08x Address in process.\n", data_va);
571 printf ("\t0x%08x Offset in output file.\n",
572 data_file - p_outfile->file_base);
573 printf ("\t0x%08x Size in bytes.\n", size);
574 memcpy (data_file, data_va, size);
575
576 index = (DWORD) data_file + size - (DWORD) p_outfile->file_base;
577 size = p_infile->size - index;
578 printf ("Copying rest of executable...\n");
579 printf ("\t0x%08x Offset in input file.\n", index);
580 printf ("\t0x%08x Offset in output file.\n", index);
581 printf ("\t0x%08x Size in bytes.\n", size);
582 memcpy ((char *) p_outfile->file_base + index,
583 (char *) p_infile->file_base + index, size);
584}
585 671
586static void 672 for (i = 0; i < debug_dir.Size; i++, debug_entry++)
587dump_bss_and_heap (file_data *p_infile, file_data *p_outfile) 673 ADJUST_OFFSET (debug_entry->PointerToRawData);
588{ 674 }
589 unsigned char *heap_data, *bss_data; 675 }
590 unsigned long size, index;
591
592 printf ("Dumping heap into executable...\n");
593
594 index = heap_index_in_executable;
595 size = get_committed_heap_size ();
596 heap_data = get_heap_start ();
597
598 printf ("\t0x%08x Heap start in process.\n", heap_data);
599 printf ("\t0x%08x Heap offset in executable.\n", index);
600 printf ("\t0x%08x Heap size in bytes.\n", size);
601
602 memcpy ((PUCHAR) p_outfile->file_base + index, heap_data, size);
603
604 printf ("Dumping .bss into executable...\n");
605
606 index += size;
607 size = bss_size;
608 bss_data = bss_start;
609
610 printf ("\t0x%08x BSS start in process.\n", bss_data);
611 printf ("\t0x%08x BSS offset in executable.\n", index);
612 printf ("\t0x%08x BSS size in bytes.\n", size);
613 memcpy ((char *) p_outfile->file_base + index, bss_data, size);
614} 676}
615 677
616 678
617/* Reload and remap routines. */ 679/* Dump out .data and .bss sections into a new executable. */
618
619void 680void
620w32_fatal_reload_error (char *step) 681unexec (char *new_name, char *old_name, void *start_data, void *start_bss,
682 void *entry_address)
621{ 683{
622 int error = GetLastError (); 684 file_data in_file, out_file;
623 char *buffer = alloca (4096); 685 char out_filename[MAX_PATH], in_filename[MAX_PATH];
624 686 unsigned long size;
625 sprintf (buffer, 687 char *ptr;
626 "Emacs failed to load its dumped heap back into its address space.\n" 688
627 "The error occurred during the following step:\n\n" 689 /* Make sure that the input and output filenames have the
628 "%s\n\n" 690 ".exe" extension...patch them up if they don't. */
629 "GetLastError = %d\n\n" 691 strcpy (in_filename, old_name);
630 "Heap start: 0x%08x\n" 692 ptr = in_filename + strlen (in_filename) - 4;
631 "Heap commit: 0x%08x\n" 693 if (strcmp (ptr, ".exe"))
632 "Heap end: 0x%08x\n\n" 694 strcat (in_filename, ".exe");
633 "This error typically happens when the system loads a DLL into\n"
634 "the middle of Emacs' address space, preventing Emacs from\n"
635 "loading its heap there. If this happens only occasionally, then\n"
636 "you can probably ignore it. But if it happens so often that\n"
637 "you cannot get Emacs to start reliably, and you think that Emacs\n"
638 "is installed correctly, then you have a couple of options:\n\n"
639 "Emacs correctly, then you have two options:\n\n"
640 "1) You can dump Emacs yourself. By doing this, you ensure that\n"
641 "Emacs' heap fits around the DLLs in your system. To dump Emacs,\n"
642 "download the emacs-(version)-undump-(arch) distribution file\n"
643 "from the site where you downloaded the executable distribution.\n\n"
644 "2) You can build Emacs from source. This is just another way\n"
645 "to dump Emacs on your system.",
646 step,
647 error,
648 get_heap_start (),
649 get_heap_start () + get_committed_heap_size (),
650 get_heap_end ());
651
652 MessageBox (NULL,
653 buffer,
654 "Emacs Abort Dialog",
655 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
656
657 exit (-1);
658}
659 695
660/* Load the dumped .bss section into the .bss area of our address space. */ 696 strcpy (out_filename, new_name);
661void 697 ptr = out_filename + strlen (out_filename) - 4;
662read_in_bss (char *filename) 698 if (strcmp (ptr, ".exe"))
663{ 699 strcat (out_filename, ".exe");
664 HANDLE file;
665 unsigned long size, index, n_read, total_read;
666 char buffer[512], *bss;
667 int i;
668 700
669 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL, 701 printf ("Dumping from %s\n", in_filename);
670 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 702 printf (" to %s\n", out_filename);
671 if (file == INVALID_HANDLE_VALUE)
672 w32_fatal_reload_error ("Opening Emacs executable file for .bss.");
673 703
674 /* Seek to where the .bss section is tucked away after the heap... */ 704 /* We need to round off our heap to NT's page size. */
675 index = heap_index_in_executable + get_committed_heap_size (); 705 round_heap (get_page_size ());
676 if (SetFilePointer (file, index, NULL, FILE_BEGIN) == 0xFFFFFFFF)
677 w32_fatal_reload_error ("Seeking to the saved .bss section.");
678
679 /* Ok, read in the saved .bss section and initialize all
680 uninitialized variables. */
681 if (!ReadFile (file, bss_start, bss_size, &n_read, NULL))
682 w32_fatal_reload_error ("Reading the saved .bss section.");
683 706
684 CloseHandle (file); 707 /* Open the undumped executable file. */
685} 708 if (!open_input_file (&in_file, in_filename))
709 {
710 printf ("Failed to open %s (%d)...bailing.\n",
711 in_filename, GetLastError ());
712 exit (1);
713 }
686 714
687/* Map the heap dumped into the executable file into our address space. */ 715 /* Get the interesting section info, like start and size of .bss... */
688void 716 get_section_info (&in_file);
689map_in_heap (char *filename)
690{
691 HANDLE file;
692 HANDLE file_mapping;
693 void *file_base;
694 unsigned long size, upper_size, n_read;
695 int i;
696 717
697 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL, 718 /* The size of the dumped executable is the size of the original
698 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 719 executable plus the size of the heap and the size of the .bss section. */
699 if (file == INVALID_HANDLE_VALUE) 720 size = in_file.size +
700 w32_fatal_reload_error ("Opening Emacs executable file for heap."); 721 get_committed_heap_size () +
701 722 extra_bss_size +
702 size = GetFileSize (file, &upper_size); 723 extra_bss_size_static;
703 file_mapping = CreateFileMapping (file, NULL, PAGE_WRITECOPY, 724 if (!open_output_file (&out_file, out_filename, size))
704 0, size, NULL);
705 if (!file_mapping)
706 w32_fatal_reload_error ("Creating file mapping to heap in executable.");
707
708 size = get_committed_heap_size ();
709 file_base = MapViewOfFileEx (file_mapping, FILE_MAP_COPY, 0,
710 heap_index_in_executable, size,
711 get_heap_start ());
712 if (file_base != 0)
713 { 725 {
714 return; 726 printf ("Failed to open %s (%d)...bailing.\n",
727 out_filename, GetLastError ());
728 exit (1);
715 } 729 }
716 730
717 /* If we don't succeed with the mapping, then copy from the 731 /* Set the flag (before dumping). */
718 data into the heap. */ 732 using_dynamic_heap = TRUE;
719 733
720 CloseHandle (file_mapping); 734 copy_executable_and_dump_data (&in_file, &out_file);
721 735
722 if (VirtualAlloc (get_heap_start (), get_committed_heap_size (), 736 /* Patch up header fields; profiler is picky about this. */
723 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE) == NULL) 737 {
724 w32_fatal_reload_error ("Allocating heap address space."); 738 PIMAGE_DOS_HEADER dos_header;
739 PIMAGE_NT_HEADERS nt_header;
740 HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
741 DWORD headersum;
742 DWORD checksum;
725 743
726 /* Seek to the location of the heap data in the executable. */ 744 dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
727 i = heap_index_in_executable; 745 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
728 if (SetFilePointer (file, i, NULL, FILE_BEGIN) == 0xFFFFFFFF)
729 w32_fatal_reload_error ("Seeking to saved heap in executable file.");
730 746
731 /* Read in the data. */ 747 nt_header->OptionalHeader.CheckSum = 0;
732 if (!ReadFile (file, get_heap_start (), 748// nt_header->FileHeader.TimeDateStamp = time (NULL);
733 get_committed_heap_size (), &n_read, NULL)) 749// dos_header->e_cp = size / 512;
734 w32_fatal_reload_error ("Reading saved heap from executable file."); 750// nt_header->OptionalHeader.SizeOfImage = size;
751
752 pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
753 if (pfnCheckSumMappedFile)
754 {
755// nt_header->FileHeader.TimeDateStamp = time (NULL);
756 pfnCheckSumMappedFile (out_file.file_base,
757 out_file.size,
758 &headersum,
759 &checksum);
760 nt_header->OptionalHeader.CheckSum = checksum;
761 }
762 FreeLibrary (hImagehelp);
763 }
735 764
736 CloseHandle (file); 765 close_file_data (&in_file);
766 close_file_data (&out_file);
737} 767}
768
769/* eof */