diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/unexw32.c | 908 |
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. */ |
| 58 | BOOL need_to_recreate_heap = FALSE; | 58 | BOOL using_dynamic_heap = FALSE; |
| 59 | |||
| 60 | /* So we can find our heap in the file to recreate it. */ | ||
| 61 | unsigned long heap_index_in_executable = 0; | ||
| 62 | 59 | ||
| 63 | int open_input_file (file_data *p_file, char *name); | 60 | int open_input_file (file_data *p_file, char *name); |
| 64 | int open_output_file (file_data *p_file, char *name, unsigned long size); | 61 | int open_output_file (file_data *p_file, char *name, unsigned long size); |
| 65 | void close_file_data (file_data *p_file); | 62 | void close_file_data (file_data *p_file); |
| 66 | 63 | ||
| 67 | void get_section_info (file_data *p_file); | 64 | void get_section_info (file_data *p_file); |
| 68 | void copy_executable_and_dump_data_section (file_data *, file_data *); | 65 | void copy_executable_and_dump_data (file_data *, file_data *); |
| 69 | void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile); | 66 | void 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. */ |
| 72 | PUCHAR data_start_va = 0; | 69 | PIMAGE_SECTION_HEADER data_section; |
| 73 | DWORD data_start_file = 0; | 70 | PUCHAR data_start = 0; |
| 74 | DWORD data_size = 0; | 71 | DWORD 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. */ |
| 74 | PIMAGE_SECTION_HEADER bss_section; | ||
| 77 | PUCHAR bss_start = 0; | 75 | PUCHAR bss_start = 0; |
| 78 | DWORD bss_size = 0; | 76 | DWORD bss_size = 0; |
| 77 | DWORD extra_bss_size = 0; | ||
| 78 | /* bss data that is static might be discontiguous from non-static. */ | ||
| 79 | PIMAGE_SECTION_HEADER bss_section_static; | ||
| 80 | PUCHAR bss_start_static = 0; | ||
| 81 | DWORD bss_size_static = 0; | ||
| 82 | DWORD extra_bss_size_static = 0; | ||
| 83 | |||
| 84 | PIMAGE_SECTION_HEADER heap_section; | ||
| 79 | 85 | ||
| 80 | #ifdef HAVE_NTGUI | 86 | #ifdef HAVE_NTGUI |
| 81 | HINSTANCE hinst = NULL; | 87 | HINSTANCE 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. */ | ||
| 174 | void | ||
| 175 | unexec (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 | |||
| 267 | int | 141 | int |
| 268 | open_input_file (file_data *p_file, char *filename) | 142 | open_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) | |||
| 330 | void | 204 | void |
| 331 | close_file_data (file_data *p_file) | 205 | close_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 | ||
| 342 | static void | ||
| 343 | get_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 | |||
| 382 | unsigned long | ||
| 383 | get_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. */ |
| 392 | IMAGE_SECTION_HEADER * | 219 | IMAGE_SECTION_HEADER * |
| 393 | find_section (char * name, IMAGE_NT_HEADERS * nt_header) | 220 | find_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. */ | ||
| 266 | IMAGE_SECTION_HEADER * | ||
| 267 | offset_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). */ | ||
| 287 | static DWORD | ||
| 288 | relocate_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. */ |
| 431 | static void | 341 | static 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 | |||
| 462 | static void | ||
| 463 | copy_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 | ||
| 548 | static void | 665 | section = rva_to_section (debug_dir.VirtualAddress, dst_nt_header); |
| 549 | copy_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 | ||
| 586 | static void | 672 | for (i = 0; i < debug_dir.Size; i++, debug_entry++) |
| 587 | dump_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 | |||
| 619 | void | 680 | void |
| 620 | w32_fatal_reload_error (char *step) | 681 | unexec (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); |
| 661 | void | 697 | ptr = out_filename + strlen (out_filename) - 4; |
| 662 | read_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... */ |
| 688 | void | 716 | get_section_info (&in_file); |
| 689 | map_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 */ | ||