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