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