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