]> git.proxmox.com Git - mirror_edk2.git/blame - Tools/CCode/Source/GenTEImage/GenTEImage.c
To fix,
[mirror_edk2.git] / Tools / CCode / Source / GenTEImage / GenTEImage.c
CommitLineData
d25c4bf0 1/*++\r
2\r
ad1f8df0 3Copyright (c) 1999-2006 Intel Corporation. All rights reserved\r
4This program and the accompanying materials are licensed and made available \r
5under the terms and conditions of the BSD License which accompanies this \r
6distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
d25c4bf0 11\r
12Module Name:\r
13\r
14 GenTEImage.c\r
15 \r
16Abstract:\r
17\r
18 Utility program to shrink a PE32 image down by replacing\r
19 the DOS, PE, and optional headers with a minimal header.\r
20\r
21--*/\r
22\r
23#include <stdio.h>\r
24#include <string.h>\r
25#include <stdlib.h>\r
26\r
ce53a8c3 27#include <Common/UefiBaseTypes.h>\r
28#include <Common/EfiImage.h> // for PE32 structure definitions\r
51d48c26 29\r
ce53a8c3 30#include "CommonLib.h"\r
d25c4bf0 31#include "EfiUtilityMsgs.h"\r
32\r
33//\r
34// Version of this utility\r
35//\r
36#define UTILITY_NAME "GenTEImage"\r
db608e6b 37#define UTILITY_MAJOR_VERSION 0\r
38#define UTILITY_MINOR_VERSION 11\r
d25c4bf0 39\r
40//\r
41// Define the max length of a filename\r
42//\r
43#define MAX_PATH 256\r
44#define DEFAULT_OUTPUT_EXTENSION ".te"\r
45\r
46//\r
47// Use this to track our command-line options and globals\r
48//\r
49struct {\r
50 INT8 OutFileName[MAX_PATH];\r
51 INT8 InFileName[MAX_PATH];\r
52 INT8 Verbose;\r
53 INT8 Dump;\r
54} mOptions;\r
55\r
56//\r
57// Use these to convert from machine type value to a named type\r
58//\r
59typedef struct {\r
60 UINT16 Value;\r
61 INT8 *Name;\r
62} STRING_LOOKUP;\r
63\r
64static STRING_LOOKUP mMachineTypes[] = {\r
65 EFI_IMAGE_MACHINE_IA32,\r
66 "IA32",\r
67 EFI_IMAGE_MACHINE_IA64,\r
68 "IA64",\r
69 EFI_IMAGE_MACHINE_EBC,\r
70 "EBC",\r
71 0,\r
72 NULL\r
73};\r
74\r
75static STRING_LOOKUP mSubsystemTypes[] = {\r
76 EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,\r
77 "EFI application",\r
78 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER,\r
79 "EFI boot service driver",\r
80 EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER,\r
81 "EFI runtime driver",\r
82 0,\r
83 NULL\r
84};\r
85//\r
86// Function prototypes\r
87//\r
db608e6b 88static\r
89void\r
90Version (\r
91 VOID\r
92 );\r
93\r
d25c4bf0 94static\r
95void\r
96Usage (\r
97 VOID\r
98 );\r
99\r
100static\r
101STATUS\r
102ParseCommandLine (\r
103 int Argc,\r
104 char *Argv[]\r
105 );\r
106\r
107static\r
108STATUS\r
109CheckPE32File (\r
110 INT8 *FileName,\r
111 FILE *Fptr,\r
112 UINT16 *MachineType,\r
113 UINT16 *SubSystem\r
114 );\r
115\r
116static\r
117STATUS\r
118ProcessFile (\r
119 INT8 *InFileName,\r
120 INT8 *OutFileName\r
121 );\r
122\r
123static\r
124void\r
125DumpImage (\r
126 INT8 *FileName\r
127 );\r
128\r
129static\r
130INT8 *\r
131GetMachineTypeStr (\r
132 UINT16 MachineType\r
133 );\r
134\r
135static\r
136INT8 *\r
137GetSubsystemTypeStr (\r
138 UINT16 SubsystemType\r
139 );\r
140\r
141main (\r
142 int Argc,\r
143 char *Argv[]\r
144 )\r
145/*++\r
146\r
147Routine Description:\r
148 \r
149\r
150Arguments:\r
151\r
152 Argc - standard C main() argument count\r
153\r
154 Argv - standard C main() argument list\r
155\r
156Returns:\r
157\r
158 0 success\r
159 non-zero otherwise\r
160\r
161--*/\r
162// GC_TODO: ] - add argument and description to function comment\r
163{\r
164 INT8 *Ext;\r
165 UINT32 Status;\r
166\r
167 SetUtilityName (UTILITY_NAME);\r
168 //\r
169 // Parse the command line arguments\r
170 //\r
171 if (ParseCommandLine (Argc, Argv)) {\r
172 return STATUS_ERROR;\r
173 }\r
174 //\r
175 // If dumping an image, then do that and quit\r
176 //\r
177 if (mOptions.Dump) {\r
178 DumpImage (mOptions.InFileName);\r
179 goto Finish;\r
180 }\r
181 //\r
182 // Determine the output filename. Either what they specified on\r
183 // the command line, or the first input filename with a different extension.\r
184 //\r
185 if (!mOptions.OutFileName[0]) {\r
186 strcpy (mOptions.OutFileName, mOptions.InFileName);\r
187 //\r
188 // Find the last . on the line and replace the filename extension with\r
189 // the default\r
190 //\r
191 for (Ext = mOptions.OutFileName + strlen (mOptions.OutFileName) - 1;\r
192 (Ext >= mOptions.OutFileName) && (*Ext != '.') && (*Ext != '\\');\r
193 Ext--\r
194 )\r
195 ;\r
196 //\r
197 // If dot here, then insert extension here, otherwise append\r
198 //\r
199 if (*Ext != '.') {\r
200 Ext = mOptions.OutFileName + strlen (mOptions.OutFileName);\r
201 }\r
202\r
203 strcpy (Ext, DEFAULT_OUTPUT_EXTENSION);\r
204 }\r
205 //\r
206 // Make sure we don't have the same filename for input and output files\r
207 //\r
208 if (stricmp (mOptions.OutFileName, mOptions.InFileName) == 0) {\r
209 Error (NULL, 0, 0, mOptions.OutFileName, "input and output file names must be different");\r
210 goto Finish;\r
211 }\r
212 //\r
213 // Process the file\r
214 //\r
215 ProcessFile (mOptions.InFileName, mOptions.OutFileName);\r
216Finish:\r
217 Status = GetUtilityStatus ();\r
218 return Status;\r
219}\r
220\r
221static\r
222STATUS\r
223ProcessFile (\r
224 INT8 *InFileName,\r
225 INT8 *OutFileName\r
226 )\r
227/*++\r
228\r
229Routine Description:\r
230 \r
231 Process a PE32 EFI file.\r
232\r
233Arguments:\r
234 \r
235 InFileName - the file name pointer to the input file\r
236 OutFileName - the file name pointer to the output file\r
237\r
238Returns:\r
239\r
240 STATUS_SUCCESS - the process has been finished successfully\r
241 STATUS_ERROR - error occured during the processing\r
242\r
243--*/\r
244{\r
245 STATUS Status;\r
246 FILE *InFptr;\r
247 FILE *OutFptr;\r
248 UINT16 MachineType;\r
249 UINT16 SubSystem;\r
250 EFI_TE_IMAGE_HEADER TEImageHeader;\r
251 UINT32 PESigOffset;\r
252 EFI_IMAGE_FILE_HEADER FileHeader;\r
253 EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader32;\r
254 EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader64;\r
255 UINT32 BytesStripped;\r
256 UINT32 FileSize;\r
257 UINT8 *Buffer;\r
258 long SaveFilePosition;\r
259\r
260 InFptr = NULL;\r
261 OutFptr = NULL;\r
262 Buffer = NULL;\r
263 Status = STATUS_ERROR;\r
264\r
265 //\r
266 // Try to open the input file\r
267 //\r
268 if ((InFptr = fopen (InFileName, "rb")) == NULL) {\r
269 Error (NULL, 0, 0, InFileName, "failed to open input file for reading");\r
270 return STATUS_ERROR;\r
271 }\r
272 //\r
273 // Double-check the file to make sure it's what we expect it to be\r
274 //\r
275 if (CheckPE32File (InFileName, InFptr, &MachineType, &SubSystem) != STATUS_SUCCESS) {\r
276 goto Finish;\r
277 }\r
278 //\r
279 // Initialize our new header\r
280 //\r
281 memset (&TEImageHeader, 0, sizeof (EFI_TE_IMAGE_HEADER));\r
282\r
283 //\r
284 // Seek to the end to get the file size\r
285 //\r
286 fseek (InFptr, 0, SEEK_END);\r
287 FileSize = ftell (InFptr);\r
288 fseek (InFptr, 0, SEEK_SET);\r
289\r
290 //\r
291 // Per the PE/COFF specification, at offset 0x3C in the file is a 32-bit\r
292 // offset (from the start of the file) to the PE signature, which always\r
293 // follows the MSDOS stub. The PE signature is immediately followed by the\r
294 // COFF file header.\r
295 //\r
296 //\r
297 if (fseek (InFptr, 0x3C, SEEK_SET) != 0) {\r
298 Error (NULL, 0, 0, InFileName, "failed to seek to PE signature in file", NULL);\r
299 goto Finish;\r
300 }\r
301\r
302 if (fread (&PESigOffset, sizeof (PESigOffset), 1, InFptr) != 1) {\r
303 Error (NULL, 0, 0, InFileName, "failed to read PE signature offset from file");\r
304 goto Finish;\r
305 }\r
306\r
307 if (fseek (InFptr, PESigOffset + 4, SEEK_SET) != 0) {\r
308 Error (NULL, 0, 0, InFileName, "failed to seek to PE signature");\r
309 goto Finish;\r
310 }\r
311 //\r
312 // We should now be at the COFF file header. Read it in and verify it's\r
313 // of an image type we support.\r
314 //\r
315 if (fread (&FileHeader, sizeof (EFI_IMAGE_FILE_HEADER), 1, InFptr) != 1) {\r
316 Error (NULL, 0, 0, InFileName, "failed to read file header from image");\r
317 goto Finish;\r
318 }\r
319\r
320 if ((FileHeader.Machine != EFI_IMAGE_MACHINE_IA32) && (FileHeader.Machine != EFI_IMAGE_MACHINE_IA64)) {\r
321 Error (NULL, 0, 0, InFileName, "image is of an unsupported machine type 0x%X", (UINT32) FileHeader.Machine);\r
322 goto Finish;\r
323 }\r
324 //\r
325 // Calculate the total number of bytes we're going to strip off. The '4' is for the\r
326 // PE signature PE\0\0. Then sanity check the size.\r
327 //\r
328 BytesStripped = PESigOffset + 4 + sizeof (EFI_IMAGE_FILE_HEADER) + FileHeader.SizeOfOptionalHeader;\r
329 if (BytesStripped >= FileSize) {\r
330 Error (NULL, 0, 0, InFileName, "attempt to strip more bytes than the total file size");\r
331 goto Finish;\r
332 }\r
333\r
334 if (BytesStripped &~0xFFFF) {\r
335 Error (NULL, 0, 0, InFileName, "attempt to strip more than 64K bytes", NULL);\r
336 goto Finish;\r
337 }\r
338\r
339 TEImageHeader.StrippedSize = (UINT16) BytesStripped;\r
340\r
341 //\r
342 // Read in the optional header. Assume PE32, and if not, then re-read as PE32+\r
343 //\r
344 SaveFilePosition = ftell (InFptr);\r
345 if (fread (&OptionalHeader32, sizeof (EFI_IMAGE_OPTIONAL_HEADER32), 1, InFptr) != 1) {\r
346 Error (NULL, 0, 0, InFileName, "failed to read optional header from input file");\r
347 goto Finish;\r
348 }\r
349\r
350 if (OptionalHeader32.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
351 //\r
352 // Fill in our new header with required data directory entries\r
353 //\r
354 TEImageHeader.AddressOfEntryPoint = OptionalHeader32.AddressOfEntryPoint;\r
355 //\r
356 // - BytesStripped + sizeof (EFI_TE_IMAGE_HEADER);\r
357 //\r
358 // We're going to pack the subsystem into 1 byte. Make sure it fits\r
359 //\r
360 if (OptionalHeader32.Subsystem &~0xFF) {\r
361 Error (\r
362 NULL,\r
363 0,\r
364 0,\r
365 InFileName,\r
366 NULL,\r
367 "image subsystem 0x%X cannot be packed into 1 byte",\r
368 (UINT32) OptionalHeader32.Subsystem\r
369 );\r
370 goto Finish;\r
371 }\r
372\r
373 TEImageHeader.Subsystem = (UINT8) OptionalHeader32.Subsystem;\r
374 TEImageHeader.BaseOfCode = OptionalHeader32.BaseOfCode;\r
375 TEImageHeader.ImageBase = (UINT64) (OptionalHeader32.ImageBase + TEImageHeader.StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));\r
376 if (OptionalHeader32.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
377 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = OptionalHeader32.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;\r
378 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = OptionalHeader32.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;\r
379 }\r
380\r
381 if (OptionalHeader32.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
382 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = OptionalHeader32.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;\r
383 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = OptionalHeader32.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size;\r
384 }\r
385 } else if (OptionalHeader32.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
386 //\r
387 // Rewind and re-read the optional header\r
388 //\r
389 fseek (InFptr, SaveFilePosition, SEEK_SET);\r
390 if (fread (&OptionalHeader64, sizeof (EFI_IMAGE_OPTIONAL_HEADER64), 1, InFptr) != 1) {\r
391 Error (NULL, 0, 0, InFileName, "failed to re-read optional header from input file");\r
392 goto Finish;\r
393 }\r
394\r
395 TEImageHeader.AddressOfEntryPoint = OptionalHeader64.AddressOfEntryPoint;\r
396 //\r
397 // - BytesStripped + sizeof (EFI_TE_IMAGE_HEADER);\r
398 //\r
399 // We're going to pack the subsystem into 1 byte. Make sure it fits\r
400 //\r
401 if (OptionalHeader64.Subsystem &~0xFF) {\r
402 Error (\r
403 NULL,\r
404 0,\r
405 0,\r
406 InFileName,\r
407 NULL,\r
408 "image subsystem 0x%X cannot be packed into 1 byte",\r
409 (UINT32) OptionalHeader64.Subsystem\r
410 );\r
411 goto Finish;\r
412 }\r
413\r
414 TEImageHeader.Subsystem = (UINT8) OptionalHeader64.Subsystem;\r
415 TEImageHeader.BaseOfCode = OptionalHeader32.BaseOfCode;\r
416 TEImageHeader.ImageBase = (UINT64) (OptionalHeader64.ImageBase + TEImageHeader.StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));\r
417 if (OptionalHeader64.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
418 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = OptionalHeader64.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;\r
419 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = OptionalHeader64.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;\r
420 }\r
421\r
422 if (OptionalHeader64.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
423 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = OptionalHeader64.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;\r
424 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = OptionalHeader64.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size;\r
425 }\r
426 } else {\r
427 Error (\r
428 NULL,\r
429 0,\r
430 0,\r
431 InFileName,\r
432 "unsupported magic number 0x%X found in optional header",\r
433 (UINT32) OptionalHeader32.Magic\r
434 );\r
435 goto Finish;\r
436 }\r
437 //\r
438 // Fill in the remainder of our new image header\r
439 //\r
440 TEImageHeader.Signature = EFI_TE_IMAGE_HEADER_SIGNATURE;\r
441 TEImageHeader.Machine = FileHeader.Machine;\r
442 //\r
443 // We're going to pack the number of sections into a single byte. Make sure it fits.\r
444 //\r
445 if (FileHeader.NumberOfSections &~0xFF) {\r
446 Error (\r
447 NULL,\r
448 0,\r
449 0,\r
450 InFileName,\r
451 NULL,\r
452 "image's number of sections 0x%X cannot be packed into 1 byte",\r
453 (UINT32) FileHeader.NumberOfSections\r
454 );\r
455 goto Finish;\r
456 }\r
457\r
458 TEImageHeader.NumberOfSections = (UINT8) FileHeader.NumberOfSections;\r
459\r
460 //\r
461 // Now open our output file\r
462 //\r
463 if ((OutFptr = fopen (OutFileName, "wb")) == NULL) {\r
464 Error (NULL, 0, 0, OutFileName, "failed to open output file for writing");\r
465 goto Finish;\r
466 }\r
467 //\r
468 // Write the TE header\r
469 //\r
470 if (fwrite (&TEImageHeader, sizeof (EFI_TE_IMAGE_HEADER), 1, OutFptr) != 1) {\r
471 Error (NULL, 0, 0, "failed to write image header to output file", NULL);\r
472 goto Finish;\r
473 }\r
474 //\r
475 // Position into the input file, read the part we're not stripping, and\r
476 // write it out.\r
477 //\r
478 fseek (InFptr, BytesStripped, SEEK_SET);\r
479 Buffer = (UINT8 *) malloc (FileSize - BytesStripped);\r
480 if (Buffer == NULL) {\r
481 Error (NULL, 0, 0, "application error", "failed to allocate memory");\r
482 goto Finish;\r
483 }\r
484\r
485 if (fread (Buffer, FileSize - BytesStripped, 1, InFptr) != 1) {\r
486 Error (NULL, 0, 0, InFileName, "failed to read remaining contents of input file");\r
487 goto Finish;\r
488 }\r
489\r
490 if (fwrite (Buffer, FileSize - BytesStripped, 1, OutFptr) != 1) {\r
491 Error (NULL, 0, 0, OutFileName, "failed to write all bytes to output file");\r
492 goto Finish;\r
493 }\r
494\r
495 Status = STATUS_SUCCESS;\r
496\r
497Finish:\r
498 if (InFptr != NULL) {\r
499 fclose (InFptr);\r
500 }\r
501 //\r
502 // Close the output file. If there was an error, delete the output file so\r
503 // that a subsequent build will rebuild it.\r
504 //\r
505 if (OutFptr != NULL) {\r
506 fclose (OutFptr);\r
507 if (GetUtilityStatus () == STATUS_ERROR) {\r
508 remove (OutFileName);\r
509 }\r
510 }\r
511\r
512 //\r
513 // Free up our buffer\r
514 //\r
515 if (Buffer != NULL) {\r
516 free (Buffer);\r
517 }\r
518\r
519 return Status;\r
520}\r
521\r
522static\r
523STATUS\r
524CheckPE32File (\r
525 INT8 *FileName,\r
526 FILE *Fptr,\r
527 UINT16 *MachineType,\r
528 UINT16 *SubSystem\r
529 )\r
530/*++\r
531\r
532Routine Description:\r
533\r
534 GC_TODO: Add function description\r
535\r
536Arguments:\r
537\r
538 FileName - GC_TODO: add argument description\r
539 Fptr - GC_TODO: add argument description\r
540 MachineType - GC_TODO: add argument description\r
541 SubSystem - GC_TODO: add argument description\r
542\r
543Returns:\r
544\r
545 GC_TODO: add return values\r
546\r
547--*/\r
548{\r
549 /*++\r
550\r
551Routine Description:\r
552 \r
553 Given a file pointer to a supposed PE32 image file, verify that it is indeed a\r
554 PE32 image file, and then return the machine type in the supplied pointer.\r
555\r
556Arguments:\r
557\r
558 Fptr File pointer to the already-opened PE32 file\r
559 MachineType Location to stuff the machine type of the PE32 file. This is needed\r
560 because the image may be Itanium-based, IA32, or EBC.\r
561\r
562Returns:\r
563\r
564 0 success\r
565 non-zero otherwise\r
566\r
567--*/\r
568 EFI_IMAGE_DOS_HEADER DosHeader;\r
569 EFI_IMAGE_FILE_HEADER FileHdr;\r
570 EFI_IMAGE_OPTIONAL_HEADER OptionalHdr;\r
571 UINT32 PESig;\r
572 STATUS Status;\r
573\r
574 Status = STATUS_ERROR;\r
575 //\r
576 // Position to the start of the file\r
577 //\r
578 fseek (Fptr, 0, SEEK_SET);\r
579 //\r
580 // Read the DOS header\r
581 //\r
582 if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) {\r
583 Error (NULL, 0, 0, FileName, "failed to read the DOS stub from the input file");\r
584 goto Finish;\r
585 }\r
586 //\r
587 // Check the magic number (0x5A4D)\r
588 //\r
589 if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
590 Error (NULL, 0, 0, FileName, "input file does not appear to be a PE32 image (magic number)");\r
591 goto Finish;\r
592 }\r
593 //\r
594 // Position into the file and check the PE signature\r
595 //\r
596 fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET);\r
597 if (fread (&PESig, sizeof (PESig), 1, Fptr) != 1) {\r
598 Error (NULL, 0, 0, FileName, "failed to read PE signature bytes");\r
599 goto Finish;\r
600 }\r
601 //\r
602 // Check the PE signature in the header "PE\0\0"\r
603 //\r
604 if (PESig != EFI_IMAGE_NT_SIGNATURE) {\r
605 Error (NULL, 0, 0, FileName, "file does not appear to be a PE32 image (signature)");\r
606 goto Finish;\r
607 }\r
608 //\r
609 // Read the file header\r
610 //\r
611 if (fread (&FileHdr, sizeof (FileHdr), 1, Fptr) != 1) {\r
612 Error (NULL, 0, 0, FileName, "failed to read PE file header from input file");\r
613 goto Finish;\r
614 }\r
615 //\r
616 // Read the optional header so we can get the subsystem\r
617 //\r
618 if (fread (&OptionalHdr, sizeof (OptionalHdr), 1, Fptr) != 1) {\r
619 Error (NULL, 0, 0, FileName, "failed to read COFF optional header from input file");\r
620 goto Finish;\r
621 }\r
622\r
623 *SubSystem = OptionalHdr.Subsystem;\r
624 if (mOptions.Verbose) {\r
625 fprintf (stdout, " Got subsystem = 0x%X from image\n", (int) *SubSystem);\r
626 }\r
627 //\r
628 // Good to go\r
629 //\r
630 Status = STATUS_SUCCESS;\r
631Finish:\r
632 fseek (Fptr, 0, SEEK_SET);\r
633 return Status;\r
634}\r
635\r
636static\r
637int\r
638ParseCommandLine (\r
639 int Argc,\r
640 char *Argv[]\r
641 )\r
642/*++\r
643\r
644Routine Description:\r
645 \r
646 Given the Argc/Argv program arguments, and a pointer to an options structure,\r
647 parse the command-line options and check their validity.\r
648\r
649\r
650Arguments:\r
651\r
652 Argc - standard C main() argument count\r
653 Argv - standard C main() argument list\r
654\r
655Returns:\r
656\r
657 STATUS_SUCCESS success\r
658 non-zero otherwise\r
659\r
660--*/\r
661// GC_TODO: ] - add argument and description to function comment\r
662{\r
663 //\r
664 // Clear out the options\r
665 //\r
666 memset ((char *) &mOptions, 0, sizeof (mOptions));\r
667 //\r
668 // Skip over the program name\r
669 //\r
670 Argc--;\r
671 Argv++;\r
672 //\r
673 // If no arguments, assume they want usage info\r
674 //\r
675 if (Argc == 0) {\r
676 Usage ();\r
677 return STATUS_ERROR;\r
678 }\r
db608e6b 679 \r
680 if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) ||\r
681 (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) {\r
682 Usage();\r
683 return STATUS_ERROR;\r
684 }\r
685 \r
686 if ((strcmp(Argv[0], "-V") == 0) || (strcmp(Argv[0], "--version") == 0)) {\r
687 Version();\r
688 return STATUS_ERROR;\r
689 }\r
690 \r
d25c4bf0 691 //\r
692 // Process until no more arguments\r
693 //\r
ca9ea8d9 694 while ((Argc > 0) && (Argv[0][0] == '-')) {\r
d25c4bf0 695 if (stricmp (Argv[0], "-o") == 0) {\r
696 //\r
697 // Output filename specified with -o\r
698 // Make sure there's another parameter\r
699 //\r
700 if (Argc > 1) {\r
701 strcpy (mOptions.OutFileName, Argv[1]);\r
702 } else {\r
703 Error (NULL, 0, 0, Argv[0], "missing output file name with option");\r
704 Usage ();\r
705 return STATUS_ERROR;\r
706 }\r
707\r
708 Argv++;\r
709 Argc--;\r
710 } else if ((stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) {\r
711 //\r
712 // Help option\r
713 //\r
714 Usage ();\r
715 return STATUS_ERROR;\r
716 } else if (stricmp (Argv[0], "-v") == 0) {\r
717 //\r
718 // -v for verbose\r
719 //\r
720 mOptions.Verbose = 1;\r
721 } else if (stricmp (Argv[0], "-dump") == 0) {\r
722 //\r
723 // -dump for dumping an image\r
724 //\r
725 mOptions.Dump = 1;\r
726 } else {\r
727 Error (NULL, 0, 0, Argv[0], "unrecognized option");\r
728 Usage ();\r
729 return STATUS_ERROR;\r
730 }\r
731 //\r
732 // Next argument\r
733 //\r
734 Argv++;\r
735 Argc--;\r
736 }\r
737 //\r
738 // Better be one more arg for input file name\r
739 //\r
740 if (Argc == 0) {\r
741 Error (NULL, 0, 0, "input file name required", NULL);\r
742 Usage ();\r
743 return STATUS_ERROR;\r
744 }\r
745\r
746 if (Argc != 1) {\r
747 Error (NULL, 0, 0, Argv[1], "extra arguments on command line");\r
748 return STATUS_ERROR;\r
749 }\r
750\r
751 strcpy (mOptions.InFileName, Argv[0]);\r
752 return STATUS_SUCCESS;\r
753}\r
754\r
db608e6b 755static\r
756void \r
757Version(\r
758 void\r
759)\r
760/*++\r
761\r
762Routine Description:\r
763\r
764 Displays the standard utility information to SDTOUT\r
765\r
766Arguments:\r
767\r
768 None\r
769\r
770Returns:\r
771\r
772 None\r
773\r
774--*/\r
775{\r
776 printf ("%s v%d.%d -Utility to generate a TE image from an EFI PE32 image.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
777 printf ("Copyright (c) 1999-2007 Intel Corporation. All rights reserved.\n");\r
778}\r
779\r
d25c4bf0 780static\r
781void\r
782Usage (\r
783 VOID\r
784 )\r
785/*++\r
786\r
787Routine Description:\r
788 \r
789 Print usage information for this utility.\r
790\r
791Arguments:\r
792\r
793 None.\r
794\r
795Returns:\r
796\r
797 Nothing.\r
798\r
799--*/\r
800{\r
801 int Index;\r
802 static const char *Msg[] = {\r
db608e6b 803 "\nUsage: "UTILITY_NAME " {-v} {-dump} {-h|-?} {-o OutFileName} InFileName",\r
d25c4bf0 804 " [-e|-b] [FileName(s)]",\r
805 " where:",\r
db608e6b 806 " -h,--help,-?,/? to display help messages",\r
807 " -V,--version to display version information",\r
d25c4bf0 808 " -v - for verbose output",\r
809 " -dump - to dump the input file to a text file",\r
d25c4bf0 810 " -o OutFileName - to write output to OutFileName rather than InFileName"DEFAULT_OUTPUT_EXTENSION,\r
811 " InFileName - name of the input PE32 file",\r
812 "",\r
813 NULL\r
814 };\r
db608e6b 815 \r
816 Version();\r
817 \r
d25c4bf0 818 for (Index = 0; Msg[Index] != NULL; Index++) {\r
819 fprintf (stdout, "%s\n", Msg[Index]);\r
820 }\r
821}\r
822\r
823static\r
824VOID\r
825DumpImage (\r
826 INT8 *FileName\r
827 )\r
828/*++\r
829\r
830Routine Description:\r
831 \r
832 Dump a specified image information\r
833\r
834Arguments:\r
835 \r
836 FileName - File name pointer to the image to dump\r
837\r
838Returns:\r
839\r
840 Nothing.\r
841\r
842--*/\r
843{\r
844 FILE *InFptr;\r
845 EFI_TE_IMAGE_HEADER TEImageHeader;\r
846 INT8 *NamePtr;\r
847\r
848 //\r
849 // Open the input file\r
850 //\r
851 InFptr = NULL;\r
852\r
853 if ((InFptr = fopen (FileName, "rb")) == NULL) {\r
854 Error (NULL, 0, 0, FileName, "failed to open input file for reading");\r
855 return ;\r
856 }\r
857\r
858 if (fread (&TEImageHeader, sizeof (EFI_TE_IMAGE_HEADER), 1, InFptr) != 1) {\r
859 Error (NULL, 0, 0, FileName, "failed to read image header from input file");\r
860 goto Finish;\r
861 }\r
862\r
863 if (TEImageHeader.Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
864 Error (NULL, 0, 0, FileName, "Image does not appear to be a TE image (bad signature)");\r
865 goto Finish;\r
866 }\r
867 //\r
868 // Dump the header\r
869 //\r
870 fprintf (stdout, "Header (%d bytes):\n", sizeof (EFI_TE_IMAGE_HEADER));\r
871 fprintf (stdout, " Signature: 0x%04X (TE)\n", (UINT32) TEImageHeader.Signature);\r
872 NamePtr = GetMachineTypeStr (TEImageHeader.Machine);\r
873 fprintf (stdout, " Machine: 0x%04X (%s)\n", (UINT32) TEImageHeader.Machine, NamePtr);\r
874 NamePtr = GetSubsystemTypeStr (TEImageHeader.Subsystem);\r
875 fprintf (stdout, " Subsystem: 0x%02X (%s)\n", (UINT32) TEImageHeader.Subsystem, NamePtr);\r
876 fprintf (stdout, " Number of sections 0x%02X\n", (UINT32) TEImageHeader.NumberOfSections);\r
877 fprintf (stdout, " Stripped size: 0x%04X\n", (UINT32) TEImageHeader.StrippedSize);\r
878 fprintf (stdout, " Entry point: 0x%08X\n", TEImageHeader.AddressOfEntryPoint);\r
879 fprintf (stdout, " Base of code: 0x%08X\n", TEImageHeader.BaseOfCode);\r
880 fprintf (stdout, " Data directories:\n");\r
881 fprintf (\r
882 stdout,\r
883 " %8X [%8X] RVA [size] of Base Relocation Directory\n",\r
884 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,\r
885 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size\r
886 );\r
887 fprintf (\r
888 stdout,\r
889 " %8X [%8X] RVA [size] of Debug Directory\n",\r
890 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,\r
891 TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size\r
892 );\r
893\r
894Finish:\r
895 if (InFptr != NULL) {\r
896 fclose (InFptr);\r
897 }\r
898}\r
899\r
900static\r
901INT8 *\r
902GetMachineTypeStr (\r
903 UINT16 MachineType\r
904 )\r
905/*++\r
906\r
907Routine Description:\r
908\r
909 GC_TODO: Add function description\r
910\r
911Arguments:\r
912\r
913 MachineType - GC_TODO: add argument description\r
914\r
915Returns:\r
916\r
917 GC_TODO: add return values\r
918\r
919--*/\r
920{\r
921 int Index;\r
922\r
923 for (Index = 0; mMachineTypes[Index].Name != NULL; Index++) {\r
924 if (mMachineTypes[Index].Value == MachineType) {\r
925 return mMachineTypes[Index].Name;\r
926 }\r
927 }\r
928\r
929 return "unknown";\r
930}\r
931\r
932static\r
933INT8 *\r
934GetSubsystemTypeStr (\r
935 UINT16 SubsystemType\r
936 )\r
937/*++\r
938\r
939Routine Description:\r
940\r
941 GC_TODO: Add function description\r
942\r
943Arguments:\r
944\r
945 SubsystemType - GC_TODO: add argument description\r
946\r
947Returns:\r
948\r
949 GC_TODO: add return values\r
950\r
951--*/\r
952{\r
953 int Index;\r
954\r
955 for (Index = 0; mSubsystemTypes[Index].Name != NULL; Index++) {\r
956 if (mSubsystemTypes[Index].Value == SubsystemType) {\r
957 return mSubsystemTypes[Index].Name;\r
958 }\r
959 }\r
960\r
961 return "unknown";\r
962}\r