Bug fix for vc-dispatcher split.
[bpt/emacs.git] / nt / preprep.c
CommitLineData
95382f42 1/* Pro-process emacs.exe for profiling by MSVC.
62eda0e2 2 Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005,
6d344054 3 2006, 2007, 2008 Free Software Foundation, Inc.
95382f42
AI
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
4a9f99bd 9the Free Software Foundation; either version 3, or (at your option)
95382f42
AI
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
364c38d3
LK
19the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20Boston, MA 02110-1301, USA.
95382f42
AI
21
22 Andrew Innes <andrewi@harlequin.co.uk> 16-Jan-1999
23 based on code from addsection.c
24*/
25
26#include <stdlib.h>
27#include <stdio.h>
28#include <fcntl.h>
29#include <time.h>
a1375c9f
AI
30#ifdef __GNUC__
31#define _ANONYMOUS_UNION
32#define _ANONYMOUS_STRUCT
33#endif
95382f42
AI
34#include <windows.h>
35
36/* Include relevant definitions from IMAGEHLP.H, which can be found
37 in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
38
39PIMAGE_NT_HEADERS
40(__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
41 DWORD FileLength,
42 LPDWORD HeaderSum,
43 LPDWORD CheckSum);
44
45#undef min
46#undef max
47#define min(x, y) (((x) < (y)) ? (x) : (y))
48#define max(x, y) (((x) > (y)) ? (x) : (y))
49
50
51/* File handling. */
52
53typedef struct file_data {
54 char *name;
55 unsigned long size;
56 HANDLE file;
57 HANDLE file_mapping;
58 unsigned char *file_base;
59} file_data;
60
61int
62open_input_file (file_data *p_file, char *filename)
63{
64 HANDLE file;
65 HANDLE file_mapping;
66 void *file_base;
67 unsigned long size, upper_size;
68
69 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
70 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
177c0ea7 71 if (file == INVALID_HANDLE_VALUE)
95382f42
AI
72 return FALSE;
73
74 size = GetFileSize (file, &upper_size);
177c0ea7 75 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
95382f42 76 0, size, NULL);
177c0ea7 77 if (!file_mapping)
95382f42
AI
78 return FALSE;
79
80 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
177c0ea7 81 if (file_base == 0)
95382f42
AI
82 return FALSE;
83
84 p_file->name = filename;
85 p_file->size = size;
86 p_file->file = file;
87 p_file->file_mapping = file_mapping;
88 p_file->file_base = file_base;
89
90 return TRUE;
91}
92
93int
94open_output_file (file_data *p_file, char *filename, unsigned long size)
95{
96 HANDLE file;
97 HANDLE file_mapping;
98 void *file_base;
99
100 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
101 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
177c0ea7 102 if (file == INVALID_HANDLE_VALUE)
95382f42
AI
103 return FALSE;
104
177c0ea7 105 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
95382f42 106 0, size, NULL);
177c0ea7 107 if (!file_mapping)
95382f42 108 return FALSE;
177c0ea7 109
95382f42 110 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
177c0ea7 111 if (file_base == 0)
95382f42 112 return FALSE;
177c0ea7 113
95382f42
AI
114 p_file->name = filename;
115 p_file->size = size;
116 p_file->file = file;
117 p_file->file_mapping = file_mapping;
118 p_file->file_base = file_base;
119
120 return TRUE;
121}
122
123int
124open_inout_file (file_data *p_file, char *filename)
125{
126 HANDLE file;
127 HANDLE file_mapping;
128 void *file_base;
129 unsigned long size, upper_size;
130
131 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
132 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
177c0ea7 133 if (file == INVALID_HANDLE_VALUE)
95382f42
AI
134 return FALSE;
135
136 size = GetFileSize (file, &upper_size);
137 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
138 0, size, NULL);
177c0ea7 139 if (!file_mapping)
95382f42
AI
140 return FALSE;
141
142 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
177c0ea7 143 if (file_base == 0)
95382f42
AI
144 return FALSE;
145
146 p_file->name = filename;
147 p_file->size = size;
148 p_file->file = file;
149 p_file->file_mapping = file_mapping;
150 p_file->file_base = file_base;
151
152 return TRUE;
153}
154
155/* Close the system structures associated with the given file. */
156void
157close_file_data (file_data *p_file)
158{
159 UnmapViewOfFile (p_file->file_base);
160 CloseHandle (p_file->file_mapping);
161 /* For the case of output files, set final size. */
162 SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN);
163 SetEndOfFile (p_file->file);
164 CloseHandle (p_file->file);
165}
166
167
168/* Routines to manipulate NT executable file sections. */
169
170unsigned long
171get_unrounded_section_size (PIMAGE_SECTION_HEADER p_section)
172{
173 /* The true section size, before rounding, for an initialized data or
174 code section. (Supposedly some linkers swap the meaning of these
175 two values.) */
176 return min (p_section->SizeOfRawData,
177 p_section->Misc.VirtualSize);
178}
179
180/* Return pointer to section header for named section. */
181IMAGE_SECTION_HEADER *
182find_section (char * name, IMAGE_NT_HEADERS * nt_header)
183{
184 PIMAGE_SECTION_HEADER section;
185 int i;
186
187 section = IMAGE_FIRST_SECTION (nt_header);
188
189 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
190 {
191 if (strcmp (section->Name, name) == 0)
192 return section;
193 section++;
194 }
195 return NULL;
196}
197
198/* Return pointer to section header for section containing the given
199 relative virtual address. */
200IMAGE_SECTION_HEADER *
201rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
202{
203 PIMAGE_SECTION_HEADER section;
204 int i;
205
206 section = IMAGE_FIRST_SECTION (nt_header);
207
208 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
209 {
210 /* Some linkers (eg. the NT SDK linker I believe) swapped the
211 meaning of these two values - or rather, they ignored
212 VirtualSize entirely and always set it to zero. This affects
213 some very old exes (eg. gzip dated Dec 1993). Since
214 w32_executable_type relies on this function to work reliably,
215 we need to cope with this. */
216 DWORD real_size = max (section->SizeOfRawData,
217 section->Misc.VirtualSize);
218 if (rva >= section->VirtualAddress
219 && rva < section->VirtualAddress + real_size)
220 return section;
221 section++;
222 }
223 return NULL;
224}
225
226/* Return pointer to section header for section containing the given
227 offset in its raw data area. */
228IMAGE_SECTION_HEADER *
229offset_to_section (DWORD offset, IMAGE_NT_HEADERS * nt_header)
230{
231 PIMAGE_SECTION_HEADER section;
232 int i;
233
234 section = IMAGE_FIRST_SECTION (nt_header);
235
236 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
237 {
238 if (offset >= section->PointerToRawData
239 && offset < section->PointerToRawData + section->SizeOfRawData)
240 return section;
241 section++;
242 }
243 return NULL;
244}
245
246/* Return offset to an object in dst, given offset in src. We assume
247 there is at least one section in both src and dst images, and that
248 the some sections may have been added to dst (after sections in src). */
249static DWORD
250relocate_offset (DWORD offset,
251 IMAGE_NT_HEADERS * src_nt_header,
252 IMAGE_NT_HEADERS * dst_nt_header)
253{
254 PIMAGE_SECTION_HEADER src_section = IMAGE_FIRST_SECTION (src_nt_header);
255 PIMAGE_SECTION_HEADER dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
256 int i = 0;
257
258 while (offset >= src_section->PointerToRawData)
259 {
260 if (offset < src_section->PointerToRawData + src_section->SizeOfRawData)
261 break;
262 i++;
263 if (i == src_nt_header->FileHeader.NumberOfSections)
264 {
265 /* Handle offsets after the last section. */
266 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
267 dst_section += dst_nt_header->FileHeader.NumberOfSections - 1;
268 while (dst_section->PointerToRawData == 0)
269 dst_section--;
270 while (src_section->PointerToRawData == 0)
271 src_section--;
272 return offset
273 + (dst_section->PointerToRawData + dst_section->SizeOfRawData)
274 - (src_section->PointerToRawData + src_section->SizeOfRawData);
275 }
276 src_section++;
277 dst_section++;
278 }
279 return offset +
280 (dst_section->PointerToRawData - src_section->PointerToRawData);
281}
282
283#define OFFSET_TO_RVA(offset, section) \
284 (section->VirtualAddress + ((DWORD)(offset) - section->PointerToRawData))
285
286#define RVA_TO_OFFSET(rva, section) \
287 (section->PointerToRawData + ((DWORD)(rva) - section->VirtualAddress))
288
289#define RVA_TO_SECTION_OFFSET(rva, section) \
290 ((DWORD)(rva) - section->VirtualAddress)
291
292#define RVA_TO_PTR(var,section,filedata) \
293 ((void *)(RVA_TO_OFFSET(var,section) + (filedata)->file_base))
294
295/* Convert address in executing image to RVA. */
296#define PTR_TO_RVA(ptr) ((DWORD)(ptr) - (DWORD) GetModuleHandle (NULL))
297
298#define PTR_TO_OFFSET(ptr, pfile_data) \
8b1709cc 299 ((unsigned char *)(ptr) - (pfile_data)->file_base)
95382f42
AI
300
301#define OFFSET_TO_PTR(offset, pfile_data) \
302 ((pfile_data)->file_base + (DWORD)(offset))
303
304#define ROUND_UP(p, align) (((DWORD)(p) + (align)-1) & ~((align)-1))
305#define ROUND_DOWN(p, align) ((DWORD)(p) & ~((align)-1))
306
307
308/* The MSVC prep program generates a ._xe file from .exe, where relevant
309 function calls etc have been patched to go through thunks (generated
310 by prep) that record timing/call information. Because the thunks
311 need to make references to functions imported from profile.dll, the
312 import table must be expanded; the end result is that all the
313 sections following .rdata are relocated to higher RVAs (add a final
314 code section is added holding all the thunks). The .reloc section is
315 also expanded, so that the thunks themselves are relocatable.
316
317 It is this relocation which kills emacs._xe, because the dumped heap
318 pointers aren't relocated, because there is no relocation data for
319 either the relevant global/static variables or the heap section
320 itself, both of which contain pointers into the heap. [Note that
321 static variables which aren't initialized during linking may become
322 initialized with heap pointers, or even pointers to other static
323 variables, because of dumping.]
324
325 We could potentially generate the relocation data ourselves by making
326 two versions of temacs, one with an extra dummmy section before
327 EMHEAP to offset it, and then compare the dumped executables from
328 both. That is a lot of work though, and it doesn't solve the problem
329 of dumped pointers to static variables, which also can be relocated.
330
331 A better solution is to pre-process emacs.exe so that the .rdata and
332 .reloc sections are moved to the end of the section table, and thus
333 prep won't relocate anything else. (Of course, we leave "dead"
334 copies of these two sections in place, so that the virtual address of
335 everything else is unaffected.) Relocating the .reloc data is
336 trivial - we just update the IMAGE_BASE_RELOCATION address in the
337 header (the data itself doesn't change). Relocating the import table
338 is more complicated though, because the calls to imported functions
339 must be patched up. That requires us to selectively apply the base
340 relocations when we encounter references to imported functions (or
341 variables) in other sections, but at least the base relocations are
342 easy to parse. */
343
344static void
177c0ea7 345copy_executable_and_move_sections (file_data *p_infile,
95382f42
AI
346 file_data *p_outfile)
347{
348 unsigned char *dst;
349 PIMAGE_DOS_HEADER dos_header;
350 PIMAGE_NT_HEADERS nt_header;
351 PIMAGE_NT_HEADERS dst_nt_header;
352 PIMAGE_SECTION_HEADER section;
353 PIMAGE_SECTION_HEADER dst_section;
354 PIMAGE_SECTION_HEADER import_section;
355 PIMAGE_SECTION_HEADER reloc_section;
356 PIMAGE_DATA_DIRECTORY import_dir;
357 PIMAGE_DATA_DIRECTORY reloc_dir;
358 DWORD import_delta_rva;
359 DWORD reloc_delta_rva;
360 DWORD offset;
361 int i;
362
363#define COPY_CHUNK(message, src, size) \
364 do { \
365 unsigned char *s = (void *)(src); \
366 unsigned long count = (size); \
367 printf ("%s\n", (message)); \
368 printf ("\t0x%08x Offset in input file.\n", s - p_infile->file_base); \
369 printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
370 printf ("\t0x%08x Size in bytes.\n", count); \
371 memcpy (dst, s, count); \
372 dst += count; \
373 } while (0)
374
375#define DST_TO_OFFSET() PTR_TO_OFFSET (dst, p_outfile)
376#define ROUND_UP_DST_AND_ZERO(align) \
377 do { \
378 unsigned char *newdst = p_outfile->file_base \
379 + ROUND_UP (DST_TO_OFFSET (), (align)); \
380 /* Zero the alignment slop; it may actually initialize real data. */ \
381 memset (dst, 0, newdst - dst); \
382 dst = newdst; \
383 } while (0)
384
385 /* Copy the source image sequentially, ie. section by section after
386 copying the headers and section table, to simplify the process of
387 relocating the .rdata and .reloc section table entries (which might
388 force the raw section data to be relocated).
389
390 Note that dst is updated implicitly by each COPY_CHUNK. */
391
392 dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
177c0ea7 393 nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +
95382f42
AI
394 dos_header->e_lfanew);
395 section = IMAGE_FIRST_SECTION (nt_header);
177c0ea7 396
95382f42
AI
397 import_dir = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
398 import_section = rva_to_section (import_dir->VirtualAddress, nt_header);
399
400 reloc_dir = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
401 reloc_section = rva_to_section (reloc_dir->VirtualAddress, nt_header);
402 if (!reloc_section)
403 {
404 printf ("No relocation data, cannot prepare for profile prepping.\n");
405 exit (1);
406 }
407
408 dst = (unsigned char *) p_outfile->file_base;
409
410 COPY_CHUNK ("Copying DOS header...", dos_header,
411 (DWORD) nt_header - (DWORD) dos_header);
412 dst_nt_header = (PIMAGE_NT_HEADERS) dst;
413 COPY_CHUNK ("Copying NT header...", nt_header,
414 (DWORD) section - (DWORD) nt_header);
415 dst_section = (PIMAGE_SECTION_HEADER) dst;
416 COPY_CHUNK ("Copying section table...", section,
417 nt_header->FileHeader.NumberOfSections * sizeof (*section));
418
419 /* Leave room for extra section table entries; filled in below. */
420 dst += 2 * sizeof (*section);
421
422 /* Align the first section's raw data area, and set the header size
423 field accordingly. */
424 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
425 dst_nt_header->OptionalHeader.SizeOfHeaders = DST_TO_OFFSET ();
426
427 for (i = 0; i < nt_header->FileHeader.NumberOfSections;
428 i++, section++, dst_section++)
429 {
430 char msg[100];
431 sprintf (msg, "Copying raw data for %s...", section->Name);
432
433 /* "Blank out" the two sections being relocated. */
434 if (section == import_section || section == reloc_section)
435 {
436 dst_section->Name[0] = 'X';
437 dst_section->Misc.VirtualSize =
438 ROUND_UP (dst_section->Misc.VirtualSize,
439 dst_nt_header->OptionalHeader.SectionAlignment);
440 dst_section->PointerToRawData = 0;
441 dst_section->SizeOfRawData = 0;
442 dst_section->Characteristics &= ~IMAGE_SCN_CNT_INITIALIZED_DATA;
443 dst_section->Characteristics |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
444 dst_section->Characteristics &= ~IMAGE_SCN_MEM_WRITE;
445 continue;
446 }
447
448 /* Update the file-relative offset for this section's raw data (if
449 it has any) in case things have been relocated; we will update
450 the other offsets below once we know where everything is. */
451 if (dst_section->PointerToRawData)
452 dst_section->PointerToRawData = DST_TO_OFFSET ();
453
454 /* Copy the original raw data. */
455 COPY_CHUNK
456 (msg, OFFSET_TO_PTR (section->PointerToRawData, p_infile),
457 section->SizeOfRawData);
458
459 /* Round up the raw data size to the new alignment. */
460 dst_section->SizeOfRawData =
461 ROUND_UP (dst_section->SizeOfRawData,
462 dst_nt_header->OptionalHeader.FileAlignment);
463
464 /* Align the next section's raw data area. */
465 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
466 }
467
468 /* Add the extra section entries, copying the raw data we skipped
469 earlier. We'll patch up the data itself below. */
470 if (import_section != NULL)
471 {
472 dst_nt_header->FileHeader.NumberOfSections++;
473 dst_nt_header->OptionalHeader.SizeOfImage +=
474 ROUND_UP (import_section->Misc.VirtualSize,
475 dst_nt_header->OptionalHeader.SectionAlignment);
476 *dst_section = *import_section;
477 dst_section->VirtualAddress =
478 dst_section[-1].VirtualAddress
479 + ROUND_UP (dst_section[-1].Misc.VirtualSize,
480 dst_nt_header->OptionalHeader.SectionAlignment);
481 dst_section->PointerToRawData = DST_TO_OFFSET ();
482 /* Remember delta applied to import section. */
483 import_delta_rva = dst_section->VirtualAddress - import_section->VirtualAddress;
484 COPY_CHUNK
485 ("Relocating import directory",
486 OFFSET_TO_PTR (import_section->PointerToRawData, p_infile),
487 import_section->SizeOfRawData);
488 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
489 dst_section++;
490 }
491 if (reloc_section != NULL)
492 {
493 dst_nt_header->FileHeader.NumberOfSections++;
494 dst_nt_header->OptionalHeader.SizeOfImage +=
495 ROUND_UP (reloc_section->Misc.VirtualSize,
496 dst_nt_header->OptionalHeader.SectionAlignment);
497 *dst_section = *reloc_section;
498 dst_section->VirtualAddress =
499 dst_section[-1].VirtualAddress
500 + ROUND_UP (dst_section[-1].Misc.VirtualSize,
501 dst_nt_header->OptionalHeader.SectionAlignment);
502 dst_section->PointerToRawData = DST_TO_OFFSET ();
503 /* Remember delta applied to reloc section. */
504 reloc_delta_rva = dst_section->VirtualAddress - reloc_section->VirtualAddress;
505 COPY_CHUNK
506 ("Relocating base relocations directory",
507 OFFSET_TO_PTR (reloc_section->PointerToRawData, p_infile),
508 reloc_section->SizeOfRawData);
509 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
510 reloc_dir = &dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
511 reloc_dir->VirtualAddress += reloc_delta_rva;
512 dst_section++;
513 }
514
515 /* Copy remainder of source image. */
516 section--;
517 offset = ROUND_UP (section->PointerToRawData + section->SizeOfRawData,
518 nt_header->OptionalHeader.FileAlignment);
519 COPY_CHUNK
520 ("Copying remainder of executable...",
521 OFFSET_TO_PTR (offset, p_infile),
522 p_infile->size - offset);
523
524 /* Final size for new image. */
525 p_outfile->size = DST_TO_OFFSET ();
526
527 /* Now patch up remaining file-relative offsets. */
528 printf ("Patching up raw data offsets...\n");
529
530 section = IMAGE_FIRST_SECTION (nt_header);
531 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
532
533#define ADJUST_OFFSET(var) \
534 do { \
535 if ((var) != 0) \
536 (var) = relocate_offset ((var), nt_header, dst_nt_header); \
537 } while (0)
538
539#define ADJUST_IMPORT_RVA(var) \
540 do { \
541 if ((var) != 0) \
542 *((DWORD *)&(var)) += import_delta_rva; \
543 } while (0)
544
545 dst_nt_header->OptionalHeader.SizeOfInitializedData = 0;
546 dst_nt_header->OptionalHeader.SizeOfUninitializedData = 0;
547 for (i = 0; i < dst_nt_header->FileHeader.NumberOfSections; i++)
548 {
549 /* Recompute data sizes for completeness. */
550 if (dst_section[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
551 dst_nt_header->OptionalHeader.SizeOfInitializedData +=
552 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
553 else if (dst_section[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
554 dst_nt_header->OptionalHeader.SizeOfUninitializedData +=
555 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
556
557 ADJUST_OFFSET (dst_section[i].PointerToLinenumbers);
558 }
559
560 ADJUST_OFFSET (dst_nt_header->FileHeader.PointerToSymbolTable);
561
562 /* Update offsets in debug directory entries. Note that the debug
563 directory may be in the same section as the import table, so its
564 RVA may need to be adjusted too. */
565 {
566 PIMAGE_DATA_DIRECTORY debug_dir =
567 &dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
568 PIMAGE_DEBUG_DIRECTORY debug_entry;
569
570 /* Update debug_dir if part of import_section. */
571 if (rva_to_section (debug_dir->VirtualAddress, nt_header) == import_section)
572 debug_dir->VirtualAddress += import_delta_rva;
573
574 section = rva_to_section (debug_dir->VirtualAddress, dst_nt_header);
575 if (section)
576 {
577 int size;
578
579 debug_entry = RVA_TO_PTR (debug_dir->VirtualAddress, section, p_outfile);
580 size = debug_dir->Size / sizeof (IMAGE_DEBUG_DIRECTORY);
581
582 for (i = 0; i < size; i++, debug_entry++)
583 {
584 /* The debug data itself is normally not part of any
585 section, but stored after all the raw section data. So
586 let relocate_offset do the work. */
587 ADJUST_OFFSET (debug_entry->PointerToRawData);
588 ADJUST_IMPORT_RVA (debug_entry->AddressOfRawData);
589 }
590 }
591 }
592
593 /* Update RVAs in import directory entries. */
594 {
595 PIMAGE_IMPORT_DESCRIPTOR imports;
596 PIMAGE_THUNK_DATA import_thunks;
597
598 import_dir = &dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
599 import_dir->VirtualAddress += import_delta_rva;
600
601 section = rva_to_section (import_dir->VirtualAddress, dst_nt_header);
602 imports = RVA_TO_PTR (import_dir->VirtualAddress, section, p_outfile);
603
604 for ( ; imports->Name != 0; imports++)
605 {
606 ADJUST_IMPORT_RVA (imports->OriginalFirstThunk);
607 ADJUST_IMPORT_RVA (imports->FirstThunk);
608 ADJUST_IMPORT_RVA (imports->Name);
609
610 for (import_thunks = RVA_TO_PTR (imports->OriginalFirstThunk, section, p_outfile);
611 import_thunks->u1.Function != 0;
612 import_thunks++)
613 if ((import_thunks->u1.Ordinal >> 31) == 0)
614 ADJUST_IMPORT_RVA (import_thunks->u1.Ordinal);
615
616 for (import_thunks = RVA_TO_PTR (imports->FirstThunk, section, p_outfile);
617 import_thunks->u1.Function != 0;
618 import_thunks++)
619 if ((import_thunks->u1.Ordinal >> 31) == 0)
620 ADJUST_IMPORT_RVA (import_thunks->u1.Ordinal);
621 }
622
623 import_dir = &dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT];
624 import_dir->VirtualAddress += import_delta_rva;
625 }
626
627 /* Fix up references to the import section. */
628 printf ("Applying fixups to import references...\n");
629
630 {
631 IMAGE_BASE_RELOCATION *relocs, *block, *start_block, *end_block;
632 DWORD import_start = import_section->VirtualAddress + dst_nt_header->OptionalHeader.ImageBase;
633 DWORD import_end = import_start + import_section->Misc.VirtualSize;
634 DWORD len_import_relocs;
635 DWORD len_remaining_relocs;
636 int seen_high = 0;
637 WORD * high_word;
638 void * holder;
639
640 reloc_dir = &dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
641 reloc_section = rva_to_section (reloc_dir->VirtualAddress, dst_nt_header);
642 relocs = RVA_TO_PTR (reloc_dir->VirtualAddress, reloc_section, p_outfile);
643
644 /* Move the base relocations for the import section, if there are
645 any; the profiler needs to be able to patch RVAs in the import
646 section itself. */
647 for (block = relocs, start_block = 0;
648 (DWORD) block - (DWORD) relocs < reloc_dir->Size;
649 block = (void *)((DWORD) block + block->SizeOfBlock))
650 {
651 if (block->VirtualAddress >= import_section->VirtualAddress + import_section->Misc.VirtualSize)
652 {
653 end_block = block;
654 break;
655 }
656 if (block->VirtualAddress >= import_section->VirtualAddress)
657 {
658 if (start_block == 0)
659 start_block = block;
660 block->VirtualAddress += import_delta_rva;
661 }
662 }
663 if (start_block)
664 {
665 len_import_relocs = (DWORD) end_block - (DWORD) start_block;
666 len_remaining_relocs = (DWORD) relocs + reloc_dir->Size - (DWORD) end_block;
667 holder = malloc (len_import_relocs);
668 if (holder == 0)
669 abort ();
670 memcpy (holder, start_block, len_import_relocs);
671 memcpy (start_block, end_block, len_remaining_relocs);
672 memcpy ((char *) start_block + len_remaining_relocs, holder, len_import_relocs);
673 free (holder);
674 }
675
676 /* Walk up the list of base relocations, checking for references
677 to the old import section location, and patching them to
678 reference the new location. */
679 for (block = relocs;
680 (DWORD) block - (DWORD) relocs < reloc_dir->Size;
681 block = (void *)((DWORD) block + block->SizeOfBlock))
682 {
683 DWORD page_rva = block->VirtualAddress;
684 DWORD page_offset;
685 union {
686 WORD word;
687 DWORD dword;
688 } * ploc;
689 WORD *fixup;
690
691 section = rva_to_section (page_rva, dst_nt_header);
692 /* Don't apply fixups to the blanked sections. */
693 if (section->Name[0] == 'X')
694 continue;
695
696 for (fixup = (WORD *) &block[1];
697 (DWORD) fixup - (DWORD) block < block->SizeOfBlock;
698 fixup++)
699 {
700 page_offset = (*fixup) & 0xfff;
701 ploc = RVA_TO_PTR (page_rva + page_offset, section, p_outfile);
702
703 /* Unless our assumption is wrong, all low word fixups
704 should immediately follow a high fixup. */
705 if (seen_high && ((*fixup) >> 12) != IMAGE_REL_BASED_LOW)
706 abort ();
707
708 switch ((*fixup) >> 12)
709 {
710 case IMAGE_REL_BASED_ABSOLUTE:
711 break;
712 case IMAGE_REL_BASED_HIGH:
713 /* We must assume that high and low fixups occur in
714 pairs, specifically a low fixup immediately follows a
715 high fixup (normally separated by two bytes). We
716 have to process the two fixups together, to find out
717 the full pointer value and decide whether to apply
718 the fixup. */
719 seen_high = 1;
720 high_word = &ploc->word;
721 break;
722 case IMAGE_REL_BASED_LOW:
723 offset = (*high_word << 16) + ploc->word;
724 if (offset >= import_start && offset < import_end)
725 {
726 (*high_word) += import_delta_rva >> 16;
727 ploc->dword += import_delta_rva & 0xffff;
728 }
729 seen_high = 0;
730 break;
731 case IMAGE_REL_BASED_HIGHLOW:
732 /* Docs imply two words in big-endian order, so perhaps
733 this is only used on big-endian platforms, in which
734 case the obvious code will work. */
735 if (ploc->dword >= import_start && ploc->dword < import_end)
736 ploc->dword += import_delta_rva;
737 break;
738 case IMAGE_REL_BASED_HIGHADJ:
739 /* Docs don't say, but I guess this is the equivalent
740 for little-endian platforms. */
741 if (ploc->dword >= import_start && ploc->dword < import_end)
742 ploc->dword += import_delta_rva;
743 break;
744 case IMAGE_REL_BASED_MIPS_JMPADDR:
745 /* Don't know how to handle this; MIPS support has been
746 dropped from NT4 anyway. */
747 abort ();
748 break;
f78b1e5e 749#ifdef IMAGE_REL_BASED_SECTION
95382f42
AI
750 case IMAGE_REL_BASED_SECTION:
751 case IMAGE_REL_BASED_REL32:
752 /* Docs don't say what these values mean. */
3102421f
AI
753#endif
754 default:
95382f42
AI
755 abort ();
756 }
757 }
758 }
759 }
760}
761
762
763int
764main (int argc, char **argv)
765{
766 PIMAGE_DOS_HEADER dos_header;
767 PIMAGE_NT_HEADERS nt_header;
768 file_data in_file, out_file;
769 char out_filename[MAX_PATH], in_filename[MAX_PATH];
770 char *ptr;
771
772 strcpy (in_filename, argv[1]);
773 strcpy (out_filename, argv[2]);
774
775 printf ("Preparing %s for profile prepping\n", out_filename);
776
777 /* Open the original (dumped) executable file for reference. */
778 if (!open_input_file (&in_file, in_filename))
779 {
177c0ea7 780 printf ("Failed to open %s (%d)...bailing.\n",
95382f42
AI
781 in_filename, GetLastError ());
782 exit (1);
783 }
784
785 /* Create a new image that can be prepped; we don't expect the size to
786 change because we are only adding two new section table entries,
787 which should fit in the alignment slop. */
788 if (!open_output_file (&out_file, out_filename, in_file.size))
789 {
177c0ea7 790 printf ("Failed to open %s (%d)...bailing.\n",
95382f42
AI
791 out_filename, GetLastError ());
792 exit (1);
793 }
794
795 copy_executable_and_move_sections (&in_file, &out_file);
796
797 /* Patch up header fields; profiler is picky about this. */
798 {
799 HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
800 DWORD headersum;
801 DWORD checksum;
802
803 dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
804 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
805
806 nt_header->OptionalHeader.CheckSum = 0;
807// nt_header->FileHeader.TimeDateStamp = time (NULL);
808// dos_header->e_cp = size / 512;
809// nt_header->OptionalHeader.SizeOfImage = size;
810
811 pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
812 if (pfnCheckSumMappedFile)
813 {
814// nt_header->FileHeader.TimeDateStamp = time (NULL);
815 pfnCheckSumMappedFile (out_file.file_base,
816 out_file.size,
817 &headersum,
818 &checksum);
819 nt_header->OptionalHeader.CheckSum = checksum;
820 }
821 FreeLibrary (hImagehelp);
822 }
823
824 close_file_data (&out_file);
825 close_file_data (&in_file);
826
827 return 0;
828}
829
830/* eof */
ab5796a9
MB
831
832/* arch-tag: 144ca747-168e-43a0-9736-3f4c0ba1657f
833 (do not change this comment) */