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