Mercurial > emacs
comparison src/unexw32.c @ 19703:9fa57c73882d
Include config.h and time.h.
Declare extern data and functions.
(file_data): Move definition from w32heap.c.
(_start): Add debug hook for when profiling.
Spoof executable name when using profilers.
Invoke sbrk immediately when undumped.
(unexec): Print error messages when input and output dump files
cannot be opened.
Reset header checksum.
(open_input_file, open_output_file): Return status instead of aborting.
(get_section_size): Handle different linkers.
(find_section, rva_to_section): New functions.
(get_section_info) [SEPARATE_BSS_SECTION]: Make code for using
a separate .bss section conditional.
Use my_begbss and my_endbss to determine .bss size by default.
Look for Emacs data in EMDATA section.
author | Geoff Voelker <voelker@cs.washington.edu> |
---|---|
date | Wed, 03 Sep 1997 00:42:10 +0000 |
parents | bcc706aedcea |
children | c0496e62b737 |
comparison
equal
deleted
inserted
replaced
19702:e59ec4e58fce | 19703:9fa57c73882d |
---|---|
19 Boston, MA 02111-1307, USA. | 19 Boston, MA 02111-1307, USA. |
20 | 20 |
21 Geoff Voelker (voelker@cs.washington.edu) 8-12-94 | 21 Geoff Voelker (voelker@cs.washington.edu) 8-12-94 |
22 */ | 22 */ |
23 | 23 |
24 #include <config.h> | |
25 | |
24 #include <stdlib.h> /* _fmode */ | 26 #include <stdlib.h> /* _fmode */ |
25 #include <stdio.h> | 27 #include <stdio.h> |
26 #include <fcntl.h> | 28 #include <fcntl.h> |
29 #include <time.h> | |
27 #include <windows.h> | 30 #include <windows.h> |
28 | 31 |
32 /* Include relevant definitions from IMAGEHLP.H, which can be found | |
33 in \\win32sdk\mstools\samples\image\include\imagehlp.h. */ | |
34 | |
35 PIMAGE_NT_HEADERS | |
36 (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress, | |
37 DWORD FileLength, | |
38 LPDWORD HeaderSum, | |
39 LPDWORD CheckSum); | |
40 | |
29 extern BOOL ctrl_c_handler (unsigned long type); | 41 extern BOOL ctrl_c_handler (unsigned long type); |
30 | 42 |
43 extern char my_begdata[]; | |
44 extern char my_edata[]; | |
45 extern char my_begbss[]; | |
46 extern char my_endbss[]; | |
47 | |
31 #include "w32heap.h" | 48 #include "w32heap.h" |
32 | |
33 /* A convenient type for keeping all the info about a mapped file together. */ | |
34 typedef struct file_data { | |
35 char *name; | |
36 unsigned long size; | |
37 HANDLE file; | |
38 HANDLE file_mapping; | |
39 unsigned char *file_base; | |
40 } file_data; | |
41 | |
42 /* Force zero initialized variables to be placed in the .data segment; | |
43 MSVC 5.0 otherwise places them in .bss, which breaks the dumping code. */ | |
44 #pragma data_seg(".data") | |
45 | 49 |
46 /* Basically, our "initialized" flag. */ | 50 /* Basically, our "initialized" flag. */ |
47 BOOL need_to_recreate_heap = FALSE; | 51 BOOL need_to_recreate_heap = FALSE; |
48 | 52 |
49 /* So we can find our heap in the file to recreate it. */ | 53 /* So we can find our heap in the file to recreate it. */ |
50 unsigned long heap_index_in_executable = 0; | 54 unsigned long heap_index_in_executable = 0; |
51 | 55 |
52 void open_input_file (file_data *p_file, char *name); | 56 int open_input_file (file_data *p_file, char *name); |
53 void open_output_file (file_data *p_file, char *name, unsigned long size); | 57 int open_output_file (file_data *p_file, char *name, unsigned long size); |
54 void close_file_data (file_data *p_file); | 58 void close_file_data (file_data *p_file); |
55 | 59 |
56 void get_section_info (file_data *p_file); | 60 void get_section_info (file_data *p_file); |
57 void copy_executable_and_dump_data_section (file_data *, file_data *); | 61 void copy_executable_and_dump_data_section (file_data *, file_data *); |
58 void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile); | 62 void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile); |
80 void | 84 void |
81 _start (void) | 85 _start (void) |
82 { | 86 { |
83 extern void mainCRTStartup (void); | 87 extern void mainCRTStartup (void); |
84 | 88 |
89 #if 0 | |
90 /* Give us a way to debug problems with crashes on startup when | |
91 running under the MSVC profiler. */ | |
92 if (GetEnvironmentVariable ("EMACS_DEBUG", NULL, 0) > 0) | |
93 DebugBreak (); | |
94 #endif | |
95 | |
85 /* Cache system info, e.g., the NT page size. */ | 96 /* Cache system info, e.g., the NT page size. */ |
86 cache_system_info (); | 97 cache_system_info (); |
87 | 98 |
88 /* If we're a dumped version of emacs then we need to recreate | 99 /* If we're a dumped version of emacs then we need to recreate |
89 our heap and play tricks with our .bss section. Do this before | 100 our heap and play tricks with our .bss section. Do this before |
97 if (GetModuleFileName (NULL, executable_path, MAX_PATH) == 0) | 108 if (GetModuleFileName (NULL, executable_path, MAX_PATH) == 0) |
98 { | 109 { |
99 printf ("Failed to find path for executable.\n"); | 110 printf ("Failed to find path for executable.\n"); |
100 exit (1); | 111 exit (1); |
101 } | 112 } |
113 | |
114 #if 1 | |
115 /* To allow profiling, make sure executable_path names the .exe | |
116 file, not the ._xe file created by the profiler which contains | |
117 extra code that makes the stored exe offsets incorrect. (This | |
118 will not be necessary when unexec properly extends the .bss (or | |
119 .data as appropriate) section to include the dumped bss data, | |
120 and dumps the heap into a proper section of its own.) */ | |
121 { | |
122 char * p = strrchr (executable_path, '.'); | |
123 if (p && p[1] == '_') | |
124 p[1] = 'e'; | |
125 } | |
126 | |
127 /* Using HiProf profiler, exe name is different still. */ | |
128 { | |
129 char * p = strrchr (executable_path, '\\'); | |
130 strcpy (p, "\\emacs.exe"); | |
131 } | |
132 #endif | |
133 | |
102 recreate_heap (executable_path); | 134 recreate_heap (executable_path); |
103 need_to_recreate_heap = FALSE; | 135 need_to_recreate_heap = FALSE; |
136 } | |
137 else | |
138 { | |
139 /* Grab our malloc arena space now, before CRT starts up. */ | |
140 sbrk (0); | |
104 } | 141 } |
105 | 142 |
106 /* The default behavior is to treat files as binary and patch up | 143 /* The default behavior is to treat files as binary and patch up |
107 text files appropriately, in accordance with the MSDOS code. */ | 144 text files appropriately, in accordance with the MSDOS code. */ |
108 _fmode = O_BINARY; | 145 _fmode = O_BINARY; |
149 | 186 |
150 /* We need to round off our heap to NT's allocation unit (64KB). */ | 187 /* We need to round off our heap to NT's allocation unit (64KB). */ |
151 round_heap (get_allocation_unit ()); | 188 round_heap (get_allocation_unit ()); |
152 | 189 |
153 /* Open the undumped executable file. */ | 190 /* Open the undumped executable file. */ |
154 open_input_file (&in_file, in_filename); | 191 if (!open_input_file (&in_file, in_filename)) |
192 { | |
193 printf ("Failed to open %s (%d)...bailing.\n", | |
194 in_filename, GetLastError ()); | |
195 exit (1); | |
196 } | |
155 | 197 |
156 /* Get the interesting section info, like start and size of .bss... */ | 198 /* Get the interesting section info, like start and size of .bss... */ |
157 get_section_info (&in_file); | 199 get_section_info (&in_file); |
158 | 200 |
159 /* The size of the dumped executable is the size of the original | 201 /* The size of the dumped executable is the size of the original |
160 executable plus the size of the heap and the size of the .bss section. */ | 202 executable plus the size of the heap and the size of the .bss section. */ |
161 heap_index_in_executable = (unsigned long) | 203 heap_index_in_executable = (unsigned long) |
162 round_to_next ((unsigned char *) in_file.size, get_allocation_unit ()); | 204 round_to_next ((unsigned char *) in_file.size, get_allocation_unit ()); |
163 size = heap_index_in_executable + get_committed_heap_size () + bss_size; | 205 size = heap_index_in_executable + get_committed_heap_size () + bss_size; |
164 open_output_file (&out_file, out_filename, size); | 206 if (!open_output_file (&out_file, out_filename, size)) |
207 { | |
208 printf ("Failed to open %s (%d)...bailing.\n", | |
209 out_filename, GetLastError ()); | |
210 exit (1); | |
211 } | |
165 | 212 |
166 /* Set the flag (before dumping). */ | 213 /* Set the flag (before dumping). */ |
167 need_to_recreate_heap = TRUE; | 214 need_to_recreate_heap = TRUE; |
168 | 215 |
169 copy_executable_and_dump_data_section (&in_file, &out_file); | 216 copy_executable_and_dump_data_section (&in_file, &out_file); |
170 dump_bss_and_heap (&in_file, &out_file); | 217 dump_bss_and_heap (&in_file, &out_file); |
171 | 218 |
219 /* Patch up header fields; profiler is picky about this. */ | |
220 { | |
221 PIMAGE_DOS_HEADER dos_header; | |
222 PIMAGE_NT_HEADERS nt_header; | |
223 HANDLE hImagehelp = LoadLibrary ("imagehlp.dll"); | |
224 DWORD headersum; | |
225 DWORD checksum; | |
226 | |
227 dos_header = (PIMAGE_DOS_HEADER) out_file.file_base; | |
228 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew); | |
229 | |
230 nt_header->OptionalHeader.CheckSum = 0; | |
231 // nt_header->FileHeader.TimeDateStamp = time (NULL); | |
232 // dos_header->e_cp = size / 512; | |
233 // nt_header->OptionalHeader.SizeOfImage = size; | |
234 | |
235 pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile"); | |
236 if (pfnCheckSumMappedFile) | |
237 { | |
238 // nt_header->FileHeader.TimeDateStamp = time (NULL); | |
239 pfnCheckSumMappedFile (out_file.file_base, | |
240 out_file.size, | |
241 &headersum, | |
242 &checksum); | |
243 nt_header->OptionalHeader.CheckSum = checksum; | |
244 } | |
245 FreeLibrary (hImagehelp); | |
246 } | |
247 | |
172 close_file_data (&in_file); | 248 close_file_data (&in_file); |
173 close_file_data (&out_file); | 249 close_file_data (&out_file); |
174 } | 250 } |
175 | 251 |
176 | 252 |
177 /* File handling. */ | 253 /* File handling. */ |
178 | 254 |
179 | 255 |
180 void | 256 int |
181 open_input_file (file_data *p_file, char *filename) | 257 open_input_file (file_data *p_file, char *filename) |
182 { | 258 { |
183 HANDLE file; | 259 HANDLE file; |
184 HANDLE file_mapping; | 260 HANDLE file_mapping; |
185 void *file_base; | 261 void *file_base; |
186 unsigned long size, upper_size; | 262 unsigned long size, upper_size; |
187 | 263 |
188 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL, | 264 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL, |
189 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); | 265 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); |
190 if (file == INVALID_HANDLE_VALUE) | 266 if (file == INVALID_HANDLE_VALUE) |
191 { | 267 return FALSE; |
192 printf ("Failed to open %s (%d)...bailing.\n", | |
193 filename, GetLastError ()); | |
194 exit (1); | |
195 } | |
196 | 268 |
197 size = GetFileSize (file, &upper_size); | 269 size = GetFileSize (file, &upper_size); |
198 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY, | 270 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY, |
199 0, size, NULL); | 271 0, size, NULL); |
200 if (!file_mapping) | 272 if (!file_mapping) |
201 { | 273 return FALSE; |
202 printf ("Failed to create file mapping of %s (%d)...bailing.\n", | |
203 filename, GetLastError ()); | |
204 exit (1); | |
205 } | |
206 | 274 |
207 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size); | 275 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size); |
208 if (file_base == 0) | 276 if (file_base == 0) |
209 { | 277 return FALSE; |
210 printf ("Failed to map view of file of %s (%d)...bailing.\n", | |
211 filename, GetLastError ()); | |
212 exit (1); | |
213 } | |
214 | 278 |
215 p_file->name = filename; | 279 p_file->name = filename; |
216 p_file->size = size; | 280 p_file->size = size; |
217 p_file->file = file; | 281 p_file->file = file; |
218 p_file->file_mapping = file_mapping; | 282 p_file->file_mapping = file_mapping; |
219 p_file->file_base = file_base; | 283 p_file->file_base = file_base; |
220 } | 284 |
221 | 285 return TRUE; |
222 void | 286 } |
287 | |
288 int | |
223 open_output_file (file_data *p_file, char *filename, unsigned long size) | 289 open_output_file (file_data *p_file, char *filename, unsigned long size) |
224 { | 290 { |
225 HANDLE file; | 291 HANDLE file; |
226 HANDLE file_mapping; | 292 HANDLE file_mapping; |
227 void *file_base; | 293 void *file_base; |
228 int i; | |
229 | 294 |
230 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, | 295 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, |
231 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); | 296 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); |
232 if (file == INVALID_HANDLE_VALUE) | 297 if (file == INVALID_HANDLE_VALUE) |
233 { | 298 return FALSE; |
234 i = GetLastError (); | 299 |
235 printf ("open_output_file: Failed to open %s (%d).\n", | |
236 filename, i); | |
237 exit (1); | |
238 } | |
239 | |
240 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE, | 300 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE, |
241 0, size, NULL); | 301 0, size, NULL); |
242 if (!file_mapping) | 302 if (!file_mapping) |
243 { | 303 return FALSE; |
244 i = GetLastError (); | |
245 printf ("open_output_file: Failed to create file mapping of %s (%d).\n", | |
246 filename, i); | |
247 exit (1); | |
248 } | |
249 | 304 |
250 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size); | 305 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size); |
251 if (file_base == 0) | 306 if (file_base == 0) |
252 { | 307 return FALSE; |
253 i = GetLastError (); | |
254 printf ("open_output_file: Failed to map view of file of %s (%d).\n", | |
255 filename, i); | |
256 exit (1); | |
257 } | |
258 | 308 |
259 p_file->name = filename; | 309 p_file->name = filename; |
260 p_file->size = size; | 310 p_file->size = size; |
261 p_file->file = file; | 311 p_file->file = file; |
262 p_file->file_mapping = file_mapping; | 312 p_file->file_mapping = file_mapping; |
263 p_file->file_base = file_base; | 313 p_file->file_base = file_base; |
314 | |
315 return TRUE; | |
264 } | 316 } |
265 | 317 |
266 /* Close the system structures associated with the given file. */ | 318 /* Close the system structures associated with the given file. */ |
267 static void | 319 void |
268 close_file_data (file_data *p_file) | 320 close_file_data (file_data *p_file) |
269 { | 321 { |
270 UnmapViewOfFile (p_file->file_base); | 322 UnmapViewOfFile (p_file->file_base); |
271 CloseHandle (p_file->file_mapping); | 323 CloseHandle (p_file->file_mapping); |
272 CloseHandle (p_file->file); | 324 CloseHandle (p_file->file); |
312 } | 364 } |
313 *p_bss_start = (PUCHAR) start; | 365 *p_bss_start = (PUCHAR) start; |
314 *p_bss_size = (DWORD) len; | 366 *p_bss_size = (DWORD) len; |
315 } | 367 } |
316 | 368 |
317 static unsigned long | 369 unsigned long |
318 get_section_size (PIMAGE_SECTION_HEADER p_section) | 370 get_section_size (PIMAGE_SECTION_HEADER p_section) |
319 { | 371 { |
320 /* The section size is in different locations in the different versions. */ | 372 /* The true section size, before rounding. Some linkers swap the |
321 switch (get_w32_minor_version ()) | 373 meaning of these two values. */ |
322 { | 374 return min (p_section->SizeOfRawData, |
323 case 10: | 375 p_section->Misc.VirtualSize); |
324 return p_section->SizeOfRawData; | 376 } |
325 default: | 377 |
326 return p_section->Misc.VirtualSize; | 378 /* Return pointer to section header for named section. */ |
327 } | 379 IMAGE_SECTION_HEADER * |
328 } | 380 find_section (char * name, IMAGE_NT_HEADERS * nt_header) |
381 { | |
382 PIMAGE_SECTION_HEADER section; | |
383 int i; | |
384 | |
385 section = IMAGE_FIRST_SECTION (nt_header); | |
386 | |
387 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) | |
388 { | |
389 if (strcmp (section->Name, name) == 0) | |
390 return section; | |
391 section++; | |
392 } | |
393 return NULL; | |
394 } | |
395 | |
396 /* Return pointer to section header for section containing the given | |
397 relative virtual address. */ | |
398 IMAGE_SECTION_HEADER * | |
399 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header) | |
400 { | |
401 PIMAGE_SECTION_HEADER section; | |
402 int i; | |
403 | |
404 section = IMAGE_FIRST_SECTION (nt_header); | |
405 | |
406 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) | |
407 { | |
408 if (rva >= section->VirtualAddress | |
409 && rva < section->VirtualAddress + section->SizeOfRawData) | |
410 return section; | |
411 section++; | |
412 } | |
413 return NULL; | |
414 } | |
415 | |
329 | 416 |
330 /* Flip through the executable and cache the info necessary for dumping. */ | 417 /* Flip through the executable and cache the info necessary for dumping. */ |
331 static void | 418 static void |
332 get_section_info (file_data *p_infile) | 419 get_section_info (file_data *p_infile) |
333 { | 420 { |
361 | 448 |
362 /* Flip through the sections for .data and .bss ... */ | 449 /* Flip through the sections for .data and .bss ... */ |
363 section = (PIMAGE_SECTION_HEADER) IMAGE_FIRST_SECTION (nt_header); | 450 section = (PIMAGE_SECTION_HEADER) IMAGE_FIRST_SECTION (nt_header); |
364 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) | 451 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) |
365 { | 452 { |
453 #ifdef SEPARATE_BSS_SECTION | |
366 if (!strcmp (section->Name, ".bss")) | 454 if (!strcmp (section->Name, ".bss")) |
367 { | 455 { |
368 /* The .bss section. */ | 456 /* The .bss section. */ |
369 ptr = (char *) nt_header->OptionalHeader.ImageBase + | 457 ptr = (char *) nt_header->OptionalHeader.ImageBase + |
370 section->VirtualAddress; | 458 section->VirtualAddress; |
371 bss_start = ptr; | 459 bss_start = ptr; |
372 bss_size = get_section_size (section); | 460 bss_size = get_section_size (section); |
373 } | 461 } |
462 #endif | |
463 #if 0 | |
374 if (!strcmp (section->Name, ".data")) | 464 if (!strcmp (section->Name, ".data")) |
375 { | 465 { |
376 /* From lastfile.c */ | 466 /* From lastfile.c */ |
377 extern char my_edata[]; | 467 extern char my_edata[]; |
378 | 468 |
387 not any of the library data (if library data is included, | 477 not any of the library data (if library data is included, |
388 then a dumped Emacs won't run on system versions other | 478 then a dumped Emacs won't run on system versions other |
389 than the one Emacs was dumped on). */ | 479 than the one Emacs was dumped on). */ |
390 data_size = my_edata - data_start_va; | 480 data_size = my_edata - data_start_va; |
391 } | 481 } |
482 #else | |
483 if (!strcmp (section->Name, "EMDATA")) | |
484 { | |
485 /* The Emacs initialized data section. */ | |
486 data_section = section; | |
487 ptr = (char *) nt_header->OptionalHeader.ImageBase + | |
488 section->VirtualAddress; | |
489 data_start_va = ptr; | |
490 data_start_file = section->PointerToRawData; | |
491 | |
492 /* Write back the full section. */ | |
493 data_size = get_section_size (section); | |
494 } | |
495 #endif | |
392 section++; | 496 section++; |
393 } | 497 } |
394 | 498 |
395 if (!bss_start && !bss_size) | 499 #ifdef SEPARATE_BSS_SECTION |
500 if (bss_start == UNINIT_PTR && bss_size == UNINIT_LONG) | |
396 { | 501 { |
397 /* Starting with MSVC 4.0, the .bss section has been eliminated | 502 /* Starting with MSVC 4.0, the .bss section has been eliminated |
398 and appended virtually to the end of the .data section. Our | 503 and appended virtually to the end of the .data section. Our |
399 only hint about where the .bss section starts in the address | 504 only hint about where the .bss section starts in the address |
400 comes from the SizeOfRawData field in the .data section | 505 comes from the SizeOfRawData field in the .data section |
404 .bss section exactly, we have to peek into the map file. */ | 509 .bss section exactly, we have to peek into the map file. */ |
405 get_bss_info_from_map_file (p_infile, &ptr, &bss_size); | 510 get_bss_info_from_map_file (p_infile, &ptr, &bss_size); |
406 bss_start = ptr + nt_header->OptionalHeader.ImageBase | 511 bss_start = ptr + nt_header->OptionalHeader.ImageBase |
407 + data_section->VirtualAddress; | 512 + data_section->VirtualAddress; |
408 } | 513 } |
514 #else | |
515 bss_start = my_begbss; | |
516 bss_size = my_endbss - bss_start; | |
517 #endif | |
409 } | 518 } |
410 | 519 |
411 | 520 |
412 /* The dump routines. */ | 521 /* The dump routines. */ |
413 | 522 |