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