Update FwImage to zero .xdata information if the image type is X64 and all debug...
[mirror_edk2.git] / Tools / Source / TianoTools / FwImage / fwimage.c
1 /*++
2
3 Copyright (c) 2004, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 fwimage.c
15
16 Abstract:
17
18 Converts a pe32+ image to an FW image type
19
20 --*/
21
22 #include "WinNtInclude.h"
23
24 #ifndef __GNUC__
25 #include <windows.h>
26 #endif
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31
32 #include <Common/UefiBaseTypes.h>
33 #include <Common/EfiImage.h>
34
35 #include "CommonLib.h"
36 #include "EfiUtilityMsgs.c"
37
38 #define UTILITY_NAME "FwImage"
39
40 #ifdef __GNUC__
41 typedef unsigned long ULONG;
42 typedef unsigned char UCHAR;
43 typedef unsigned char *PUCHAR;
44 typedef unsigned short USHORT;
45 #endif
46
47 VOID
48 Usage (
49 VOID
50 )
51 {
52 printf ("Usage: " UTILITY_NAME " {-t time-date} [BASE|SEC|PEI_CORE|PEIM|DXE_CORE|DXE_DRIVER|DXE_RUNTIME_DRIVER|DXE_SAL_DRIVER|DXE_SMM_DRIVER|TOOL|UEFI_DRIVER|UEFI_APPLICATION|USER_DEFINED] peimage [outimage]");
53 }
54
55 static
56 STATUS
57 FCopyFile (
58 FILE *in,
59 FILE *out
60 )
61 {
62 ULONG filesize;
63 ULONG offset;
64 ULONG length;
65 UCHAR Buffer[8 * 1024];
66
67 fseek (in, 0, SEEK_END);
68 filesize = ftell (in);
69
70 fseek (in, 0, SEEK_SET);
71 fseek (out, 0, SEEK_SET);
72
73 offset = 0;
74 while (offset < filesize) {
75 length = sizeof (Buffer);
76 if (filesize - offset < length) {
77 length = filesize - offset;
78 }
79
80 fread (Buffer, length, 1, in);
81 fwrite (Buffer, length, 1, out);
82 offset += length;
83 }
84
85 if ((ULONG) ftell (out) != filesize) {
86 Error (NULL, 0, 0, "write error", NULL);
87 return STATUS_ERROR;
88 }
89
90 return STATUS_SUCCESS;
91 }
92
93 static
94 STATUS
95 FReadFile (
96 FILE *in,
97 VOID **Buffer,
98 UINTN *Length
99 )
100 {
101 fseek (in, 0, SEEK_END);
102 *Length = ftell (in);
103 *Buffer = malloc (*Length);
104 fseek (in, 0, SEEK_SET);
105 fread (*Buffer, *Length, 1, in);
106 return STATUS_SUCCESS;
107 }
108
109 static
110 STATUS
111 FWriteFile (
112 FILE *out,
113 VOID *Buffer,
114 UINTN Length
115 )
116 {
117 fseek (out, 0, SEEK_SET);
118 fwrite (Buffer, Length, 1, out);
119 if ((ULONG) ftell (out) != Length) {
120 Error (NULL, 0, 0, "write error", NULL);
121 return STATUS_ERROR;
122 }
123 free (Buffer);
124 return STATUS_SUCCESS;
125 }
126
127 int
128 main (
129 int argc,
130 char *argv[]
131 )
132 /*++
133
134 Routine Description:
135
136 Main function.
137
138 Arguments:
139
140 argc - Number of command line parameters.
141 argv - Array of pointers to command line parameter strings.
142
143 Returns:
144 STATUS_SUCCESS - Utility exits successfully.
145 STATUS_ERROR - Some error occurred during execution.
146
147 --*/
148 {
149 ULONG Type;
150 PUCHAR Ext;
151 PUCHAR p;
152 PUCHAR pe;
153 PUCHAR OutImageName;
154 UCHAR outname[500];
155 FILE *fpIn;
156 FILE *fpOut;
157 VOID *ZeroBuffer;
158 EFI_IMAGE_DOS_HEADER *DosHdr;
159 EFI_IMAGE_NT_HEADERS *PeHdr;
160 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32;
161 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64;
162 time_t TimeStamp;
163 struct tm TimeStruct;
164 EFI_IMAGE_DOS_HEADER BackupDosHdr;
165 ULONG Index;
166 ULONG Index1;
167 ULONG Index2;
168 ULONG Index3;
169 BOOLEAN TimeStampPresent;
170 UINTN AllignedRelocSize;
171 UINTN Delta;
172 EFI_IMAGE_SECTION_HEADER *SectionHeader;
173 UINT8 *FileBuffer;
174 UINTN FileLength;
175 RUNTIME_FUNCTION *RuntimeFunction;
176 UNWIND_INFO *UnwindInfo;
177
178 SetUtilityName (UTILITY_NAME);
179 //
180 // Assign to fix compile warning
181 //
182 OutImageName = NULL;
183 Type = 0;
184 Ext = 0;
185 TimeStamp = 0;
186 TimeStampPresent = FALSE;
187
188 //
189 // Look for -t time-date option first. If the time is "0", then
190 // skip it.
191 //
192 if ((argc > 2) && !strcmp (argv[1], "-t")) {
193 TimeStampPresent = TRUE;
194 if (strcmp (argv[2], "0") != 0) {
195 //
196 // Convert the string to a value
197 //
198 memset ((char *) &TimeStruct, 0, sizeof (TimeStruct));
199 if (sscanf(
200 argv[2], "%d/%d/%d,%d:%d:%d",
201 &TimeStruct.tm_mon, /* months since January - [0,11] */
202 &TimeStruct.tm_mday, /* day of the month - [1,31] */
203 &TimeStruct.tm_year, /* years since 1900 */
204 &TimeStruct.tm_hour, /* hours since midnight - [0,23] */
205 &TimeStruct.tm_min, /* minutes after the hour - [0,59] */
206 &TimeStruct.tm_sec /* seconds after the minute - [0,59] */
207 ) != 6) {
208 Error (NULL, 0, 0, argv[2], "failed to convert to mm/dd/yyyy,hh:mm:ss format");
209 return STATUS_ERROR;
210 }
211 //
212 // Now fixup some of the fields
213 //
214 TimeStruct.tm_mon--;
215 TimeStruct.tm_year -= 1900;
216 //
217 // Sanity-check values?
218 // Convert
219 //
220 TimeStamp = mktime (&TimeStruct);
221 if (TimeStamp == (time_t) - 1) {
222 Error (NULL, 0, 0, argv[2], "failed to convert time");
223 return STATUS_ERROR;
224 }
225 }
226 //
227 // Skip over the args
228 //
229 argc -= 2;
230 argv += 2;
231 }
232 //
233 // Check for enough args
234 //
235 if (argc < 3) {
236 Usage ();
237 return STATUS_ERROR;
238 }
239
240 if (argc == 4) {
241 OutImageName = argv[3];
242 }
243 //
244 // Get new image type
245 //
246 p = argv[1];
247 if (*p == '/' || *p == '\\') {
248 p += 1;
249 }
250
251 if (stricmp (p, "app") == 0 || stricmp (p, "UEFI_APPLICATION") == 0) {
252 Type = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
253 Ext = ".efi";
254
255 } else if (stricmp (p, "bsdrv") == 0 || stricmp (p, "DXE_DRIVER") == 0) {
256 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
257 Ext = ".efi";
258
259 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_RUNTIME_DRIVER") == 0) {
260 Type = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;
261 Ext = ".efi";
262
263 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_SAL_DRIVER") == 0) {
264 Type = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;
265 Ext = ".efi";
266 } else if (stricmp (p, "SEC") == 0) {
267 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
268 Ext = ".sec";
269 } else if (stricmp (p, "peim") == 0 ||
270 stricmp (p, "BASE") == 0 ||
271 stricmp (p, "PEI_CORE") == 0 ||
272 stricmp (p, "PEIM") == 0 ||
273 stricmp (p, "DXE_SMM_DRIVER") == 0 ||
274 stricmp (p, "TOOL") == 0 ||
275 stricmp (p, "UEFI_APPLICATION") == 0 ||
276 stricmp (p, "USER_DEFINED") == 0 ||
277 stricmp (p, "UEFI_DRIVER") == 0 ||
278 stricmp (p, "DXE_CORE") == 0
279 ) {
280 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
281 Ext = ".pei";
282 } else {
283 printf ("%s", p);
284 Usage ();
285 return STATUS_ERROR;
286 }
287 //
288 // open source file
289 //
290 fpIn = fopen (argv[2], "rb");
291 if (!fpIn) {
292 Error (NULL, 0, 0, argv[2], "failed to open input file for reading");
293 return STATUS_ERROR;
294 }
295
296 FReadFile (fpIn, (VOID **)&FileBuffer, &FileLength);
297
298 //
299 // Read the dos & pe hdrs of the image
300 //
301 DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;
302 if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
303 Error (NULL, 0, 0, argv[2], "DOS header signature not found in source image");
304 fclose (fpIn);
305 return STATUS_ERROR;
306 }
307
308 PeHdr = (EFI_IMAGE_NT_HEADERS *)(FileBuffer + DosHdr->e_lfanew);
309 if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {
310 Error (NULL, 0, 0, argv[2], "PE header signature not found in source image");
311 fclose (fpIn);
312 return STATUS_ERROR;
313 }
314
315 //
316 // open output file
317 //
318 strcpy (outname, argv[2]);
319 pe = NULL;
320 for (p = outname; *p; p++) {
321 if (*p == '.') {
322 pe = p;
323 }
324 }
325
326 if (!pe) {
327 pe = p;
328 }
329
330 strcpy (pe, Ext);
331
332 if (!OutImageName) {
333 OutImageName = outname;
334 }
335
336 fpOut = fopen (OutImageName, "w+b");
337 if (!fpOut) {
338 Error (NULL, 0, 0, OutImageName, "could not open output file for writing");
339 fclose (fpIn);
340 return STATUS_ERROR;
341 }
342
343 //
344 // Zero all unused fields of the DOS header
345 //
346 memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER));
347 memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER));
348 DosHdr->e_magic = BackupDosHdr.e_magic;
349 DosHdr->e_lfanew = BackupDosHdr.e_lfanew;
350
351 for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (ULONG) DosHdr->e_lfanew; Index++) {
352 FileBuffer[Index] = DosHdr->e_cp;
353 }
354
355 //
356 // Path the PE header
357 //
358 PeHdr->OptionalHeader.Subsystem = (USHORT) Type;
359 if (TimeStampPresent) {
360 PeHdr->FileHeader.TimeDateStamp = (UINT32) TimeStamp;
361 }
362
363 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
364 Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->OptionalHeader;
365 Optional32->MajorLinkerVersion = 0;
366 Optional32->MinorLinkerVersion = 0;
367 Optional32->MajorOperatingSystemVersion = 0;
368 Optional32->MinorOperatingSystemVersion = 0;
369 Optional32->MajorImageVersion = 0;
370 Optional32->MinorImageVersion = 0;
371 Optional32->MajorSubsystemVersion = 0;
372 Optional32->MinorSubsystemVersion = 0;
373 Optional32->Win32VersionValue = 0;
374 Optional32->CheckSum = 0;
375 Optional32->SizeOfStackReserve = 0;
376 Optional32->SizeOfStackCommit = 0;
377 Optional32->SizeOfHeapReserve = 0;
378 Optional32->SizeOfHeapCommit = 0;
379
380 //
381 // Strip zero padding at the end of the .reloc section
382 //
383 if (Optional32->NumberOfRvaAndSizes >= 6) {
384 if (Optional32->DataDirectory[5].Size != 0) {
385 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
386 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {
387 //
388 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
389 //
390 if (SectionHeader->VirtualAddress == Optional32->DataDirectory[5].VirtualAddress) {
391 SectionHeader->Misc.VirtualSize = Optional32->DataDirectory[5].Size;
392 AllignedRelocSize = (Optional32->DataDirectory[5].Size + Optional32->FileAlignment - 1) & (~(Optional32->FileAlignment - 1));
393 //
394 // Check to see if there is zero padding at the end of the base relocations
395 //
396 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {
397 //
398 // Check to see if the base relocations are at the end of the file
399 //
400 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional32->SizeOfImage) {
401 //
402 // All the required conditions are met to strip the zero padding of the end of the base relocations section
403 //
404 Optional32->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
405 Optional32->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
406 SectionHeader->SizeOfRawData = AllignedRelocSize;
407 FileLength = Optional32->SizeOfImage;
408 }
409 }
410 }
411 }
412 }
413 }
414 }
415 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
416 Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->OptionalHeader;
417 Optional64->MajorLinkerVersion = 0;
418 Optional64->MinorLinkerVersion = 0;
419 Optional64->MajorOperatingSystemVersion = 0;
420 Optional64->MinorOperatingSystemVersion = 0;
421 Optional64->MajorImageVersion = 0;
422 Optional64->MinorImageVersion = 0;
423 Optional64->MajorSubsystemVersion = 0;
424 Optional64->MinorSubsystemVersion = 0;
425 Optional64->Win32VersionValue = 0;
426 Optional64->CheckSum = 0;
427 Optional64->SizeOfStackReserve = 0;
428 Optional64->SizeOfStackCommit = 0;
429 Optional64->SizeOfHeapReserve = 0;
430 Optional64->SizeOfHeapCommit = 0;
431
432 //
433 // Zero the .pdata section if the machine type is X64 and the Debug Directory is empty
434 //
435 if (PeHdr->FileHeader.Machine == 0x8664) { // X64
436 if (Optional64->NumberOfRvaAndSizes >= 4) {
437 if (Optional64->NumberOfRvaAndSizes < 7 || (Optional64->NumberOfRvaAndSizes >= 7 && Optional64->DataDirectory[6].Size == 0)) {
438 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
439 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {
440 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[3].VirtualAddress) {
441 RuntimeFunction = (RUNTIME_FUNCTION *)(FileBuffer + SectionHeader->PointerToRawData);
442 for (Index1 = 0; Index1 < Optional64->DataDirectory[3].Size / sizeof (RUNTIME_FUNCTION); Index1++, RuntimeFunction++) {
443 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
444 for (Index2 = 0; Index2 < PeHdr->FileHeader.NumberOfSections; Index2++, SectionHeader++) {
445 if (RuntimeFunction->UnwindInfoAddress > SectionHeader->VirtualAddress && RuntimeFunction->UnwindInfoAddress < (SectionHeader->VirtualAddress + SectionHeader->SizeOfRawData)) {
446 UnwindInfo = (UNWIND_INFO *)(FileBuffer + SectionHeader->PointerToRawData + (RuntimeFunction->UnwindInfoAddress - SectionHeader->VirtualAddress));
447 if (UnwindInfo->Version == 1) {
448 memset (UnwindInfo + 1, 0, UnwindInfo->CountOfUnwindCodes * sizeof (UINT16));
449 memset (UnwindInfo, 0, sizeof (UNWIND_INFO));
450 }
451 }
452 }
453 memset (RuntimeFunction, 0, sizeof (RUNTIME_FUNCTION));
454 }
455 }
456 }
457 Optional64->DataDirectory[3].Size = 0;
458 Optional64->DataDirectory[3].VirtualAddress = 0;
459 }
460 }
461 }
462
463 //
464 // Strip zero padding at the end of the .reloc section
465 //
466 if (Optional64->NumberOfRvaAndSizes >= 6) {
467 if (Optional64->DataDirectory[5].Size != 0) {
468 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
469 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {
470 //
471 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
472 //
473 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[5].VirtualAddress) {
474 SectionHeader->Misc.VirtualSize = Optional64->DataDirectory[5].Size;
475 AllignedRelocSize = (Optional64->DataDirectory[5].Size + Optional64->FileAlignment - 1) & (~(Optional64->FileAlignment - 1));
476 //
477 // Check to see if there is zero padding at the end of the base relocations
478 //
479 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {
480 //
481 // Check to see if the base relocations are at the end of the file
482 //
483 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional64->SizeOfImage) {
484 //
485 // All the required conditions are met to strip the zero padding of the end of the base relocations section
486 //
487 Optional64->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
488 Optional64->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
489 SectionHeader->SizeOfRawData = AllignedRelocSize;
490 FileLength = Optional64->SizeOfImage;
491 }
492 }
493 }
494 }
495 }
496 }
497 }
498
499 FWriteFile (fpOut, FileBuffer, FileLength);
500
501 //
502 // Done
503 //
504 fclose (fpIn);
505 fclose (fpOut);
506 //
507 // printf ("Created %s\n", OutImageName);
508 //
509 return STATUS_SUCCESS;
510 }