X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=BaseTools%2FSource%2FC%2FVolInfo%2FVolInfo.c;h=ed56587058f74319dad55778fe61ef796cf05981;hb=fca5de51e1fd2f3c5ddbf5974d785f0f6b2f6c38;hp=537cea3cfe56d95656d4c601308f18deb243abff;hpb=1be2ed90a20618d71ddf34b8a07d038da0b36854;p=mirror_edk2.git
diff --git a/BaseTools/Source/C/VolInfo/VolInfo.c b/BaseTools/Source/C/VolInfo/VolInfo.c
index 537cea3cfe..ed56587058 100644
--- a/BaseTools/Source/C/VolInfo/VolInfo.c
+++ b/BaseTools/Source/C/VolInfo/VolInfo.c
@@ -1,21 +1,8 @@
/** @file
+The tool dumps the contents of a firmware volume
-Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution. The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-Module Name:
-
- VolInfo.c
-
-Abstract:
-
- The tool dumps the contents of a firmware volume
+Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -24,6 +11,11 @@ Abstract:
#include
#include
#include
+#ifdef __GNUC__
+#include
+#else
+#include
+#endif
#include
#include
@@ -43,6 +35,8 @@ Abstract:
#include "OsPath.h"
#include "ParseGuidedSectionTools.h"
#include "StringFuncs.h"
+#include "ParseInf.h"
+#include "PeCoffLib.h"
//
// Utility global variables
@@ -50,8 +44,8 @@ Abstract:
EFI_GUID gEfiCrc32GuidedSectionExtractionProtocolGuid = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID;
-#define UTILITY_MAJOR_VERSION 0
-#define UTILITY_MINOR_VERSION 82
+#define UTILITY_MAJOR_VERSION 1
+#define UTILITY_MINOR_VERSION 0
#define UTILITY_NAME "VolInfo"
@@ -77,6 +71,9 @@ EFI_HANDLE mParsedGuidedSectionTools = NULL;
CHAR8* mUtilityFilename = NULL;
+BOOLEAN EnableHash = FALSE;
+CHAR8 *OpenSslPath = NULL;
+
EFI_STATUS
ParseGuidBaseNameFile (
CHAR8 *FileName
@@ -133,11 +130,77 @@ LoadGuidedSectionToolsTxt (
IN CHAR8* FirmwareVolumeFilename
);
+EFI_STATUS
+CombinePath (
+ IN CHAR8* DefaultPath,
+ IN CHAR8* AppendPath,
+ OUT CHAR8* NewPath
+);
+
void
Usage (
VOID
);
+UINT32
+UnicodeStrLen (
+ IN CHAR16 *String
+ )
+ /*++
+
+ Routine Description:
+
+ Returns the length of a null-terminated unicode string.
+
+ Arguments:
+
+ String - The pointer to a null-terminated unicode string.
+
+ Returns:
+
+ N/A
+
+ --*/
+{
+ UINT32 Length;
+
+ for (Length = 0; *String != L'\0'; String++, Length++) {
+ ;
+ }
+ return Length;
+}
+
+VOID
+Unicode2AsciiString (
+ IN CHAR16 *Source,
+ OUT CHAR8 *Destination
+ )
+ /*++
+
+ Routine Description:
+
+ Convert a null-terminated unicode string to a null-terminated ascii string.
+
+ Arguments:
+
+ Source - The pointer to the null-terminated input unicode string.
+ Destination - The pointer to the null-terminated output ascii string.
+
+ Returns:
+
+ N/A
+
+ --*/
+{
+ while (*Source != '\0') {
+ *(Destination++) = (CHAR8) *(Source++);
+ }
+ //
+ // End the ascii with a NULL.
+ //
+ *Destination = '\0';
+}
+
int
main (
int argc,
@@ -167,41 +230,61 @@ Returns:
EFI_STATUS Status;
int Offset;
BOOLEAN ErasePolarity;
+ UINT64 LogLevel;
+ CHAR8 *OpenSslEnv;
+ CHAR8 *OpenSslCommand;
SetUtilityName (UTILITY_NAME);
//
// Print utility header
//
- printf ("%s Tiano Firmware Volume FFS image info. Version %d.%d %s, %s\n",
+ printf ("%s Version %d.%d Build %s\n",
UTILITY_NAME,
UTILITY_MAJOR_VERSION,
UTILITY_MINOR_VERSION,
- __BUILD_VERSION,
- __DATE__
+ __BUILD_VERSION
);
- //
- // Save, and then skip filename arg
- //
- mUtilityFilename = argv[0];
+ if (argc == 1) {
+ Usage ();
+ return -1;
+ }
+
argc--;
argv++;
-
+ LogLevel = 0;
Offset = 0;
+ //
+ // Look for help options
+ //
+ if ((strcmp(argv[0], "-h") == 0) || (strcmp(argv[0], "--help") == 0) ||
+ (strcmp(argv[0], "-?") == 0) || (strcmp(argv[0], "/?") == 0)) {
+ Usage();
+ return STATUS_SUCCESS;
+ }
+ //
+ // Version has already be printed, so just return success
+ //
+ if (strcmp(argv[0], "--version") == 0) {
+ return STATUS_SUCCESS;
+ }
+
//
// If they specified -x xref guid/basename cross-reference files, process it.
// This will print the basename beside each file guid. To use it, specify
// -x xref_filename to processdsc, then use xref_filename as a parameter
// here.
//
- while (argc > 2) {
+ while (argc > 0) {
if ((strcmp(argv[0], "-x") == 0) || (strcmp(argv[0], "--xref") == 0)) {
ParseGuidBaseNameFile (argv[1]);
printf("ParseGuidBaseNameFile: %s\n", argv[1]);
argc -= 2;
argv += 2;
- } else if (strcmp(argv[0], "--offset") == 0) {
+ continue;
+ }
+ if (strcmp(argv[0], "--offset") == 0) {
//
// Hex or decimal?
//
@@ -225,33 +308,88 @@ Returns:
argc -= 2;
argv += 2;
- } else {
- Usage ();
- return -1;
+ continue;
}
- }
- //
- // Check for proper number of arguments
- //
- if (argc != 1) {
- Usage ();
- return -1;
- }
- //
- // Look for help options
- //
- if ((strcmp(argv[0], "-h") == 0) || (strcmp(argv[0], "--help") == 0) ||
- (strcmp(argv[0], "-?") == 0) || (strcmp(argv[0], "/?") == 0)) {
- Usage();
- return STATUS_ERROR;
+ if ((stricmp (argv[0], "--hash") == 0)) {
+ if (EnableHash == TRUE) {
+ //
+ // --hash already given in the option, ignore this one
+ //
+ argc --;
+ argv ++;
+ continue;
+ }
+ EnableHash = TRUE;
+ OpenSslCommand = "openssl";
+ OpenSslEnv = getenv("OPENSSL_PATH");
+ if (OpenSslEnv == NULL) {
+ OpenSslPath = OpenSslCommand;
+ } else {
+ //
+ // We add quotes to the Openssl Path in case it has space characters
+ //
+ OpenSslPath = malloc(2+strlen(OpenSslEnv)+strlen(OpenSslCommand)+1);
+ if (OpenSslPath == NULL) {
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
+ return GetUtilityStatus ();
+ }
+ CombinePath(OpenSslEnv, OpenSslCommand, OpenSslPath);
+ }
+ if (OpenSslPath == NULL){
+ Error (NULL, 0, 3000, "Open SSL command not available. Please verify PATH or set OPENSSL_PATH.", NULL);
+ return GetUtilityStatus ();
+ }
+ argc --;
+ argv ++;
+ continue;
+ }
+
+ if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) {
+ SetPrintLevel (VERBOSE_LOG_LEVEL);
+ argc --;
+ argv ++;
+ continue;
+ }
+
+ if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
+ SetPrintLevel (KEY_LOG_LEVEL);
+ argc --;
+ argv ++;
+ continue;
+ }
+
+ if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
+ Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
+ return -1;
+ }
+ if (LogLevel > 9) {
+ Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, current input level is %d", (int) LogLevel);
+ return -1;
+ }
+ SetPrintLevel (LogLevel);
+ DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]);
+ argc -= 2;
+ argv += 2;
+ continue;
+ }
+
+ mUtilityFilename = argv[0];
+ argc --;
+ argv ++;
}
//
// Open the file containing the FV
//
- InputFile = fopen (LongFilePath (argv[0]), "rb");
+ if (mUtilityFilename == NULL) {
+ Error (NULL, 0, 1001, "Missing option", "Input files are not specified");
+ return GetUtilityStatus ();
+ }
+ InputFile = fopen (LongFilePath (mUtilityFilename), "rb");
if (InputFile == NULL) {
- Error (NULL, 0, 0001, "Error opening the input file", argv[0]);
+ Error (NULL, 0, 0001, "Error opening the input file", mUtilityFilename);
return GetUtilityStatus ();
}
//
@@ -266,7 +404,7 @@ Returns:
//
Status = ReadHeader (InputFile, &FvSize, &ErasePolarity);
if (EFI_ERROR (Status)) {
- Error (NULL, 0, 0003, "error parsing FV image", "%s Header is invalid", argv[0]);
+ Error (NULL, 0, 0003, "error parsing FV image", "%s Header is invalid", mUtilityFilename);
fclose (InputFile);
return GetUtilityStatus ();
}
@@ -286,12 +424,12 @@ Returns:
BytesRead = fread (FvImage, 1, FvSize, InputFile);
fclose (InputFile);
if ((unsigned int) BytesRead != FvSize) {
- Error (NULL, 0, 0004, "error reading FvImage from", argv[0]);
+ Error (NULL, 0, 0004, "error reading FvImage from", mUtilityFilename);
free (FvImage);
return GetUtilityStatus ();
}
- LoadGuidedSectionToolsTxt (argv[0]);
+ LoadGuidedSectionToolsTxt (mUtilityFilename);
PrintFvInfo (FvImage, FALSE);
@@ -397,16 +535,16 @@ GetOccupiedSize (
Routine Description:
- This function returns the next larger size that meets the alignment
+ This function returns the next larger size that meets the alignment
requirement specified.
Arguments:
ActualSize The size.
Alignment The desired alignment.
-
+
Returns:
-
+
EFI_SUCCESS Function completed successfully.
EFI_ABORTED The function encountered an error.
@@ -456,7 +594,7 @@ Returns:
//
// 0x02
//
- "EFI_SECTION_GUID_DEFINED",
+ "EFI_SECTION_GUID_DEFINED",
//
// 0x03
//
@@ -520,11 +658,11 @@ Returns:
//
// 0x12
//
- "EFI_SECTION_TE",
+ "EFI_SECTION_TE",
//
// 0x13
//
- "EFI_SECTION_DXE_DEPEX",
+ "EFI_SECTION_DXE_DEPEX",
//
// 0x14
//
@@ -591,7 +729,7 @@ ReadHeader (
Routine Description:
- This function determines the size of the FV and the erase polarity. The
+ This function determines the size of the FV and the erase polarity. The
erase polarity is the FALSE value for file state.
Arguments:
@@ -599,9 +737,9 @@ Arguments:
InputFile The file that contains the FV image.
FvSize The size of the FV.
ErasePolarity The FV erase polarity.
-
+
Returns:
-
+
EFI_SUCCESS Function completed successfully.
EFI_INVALID_PARAMETER A required parameter was NULL or is out of range.
EFI_ABORTED The function encountered an error.
@@ -613,6 +751,7 @@ Returns:
UINTN Signature[2];
UINTN BytesRead;
UINT32 Size;
+ size_t ReadSize;
BytesRead = 0;
Size = 0;
@@ -626,7 +765,10 @@ Returns:
//
// Read the header
//
- fread (&VolumeHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);
+ ReadSize = fread (&VolumeHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);
+ if (ReadSize != 1) {
+ return EFI_ABORTED;
+ }
BytesRead = sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY);
Signature[0] = VolumeHeader.Signature;
Signature[1] = 0;
@@ -750,7 +892,7 @@ Returns:
if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_64K) {
printf (" EFI_FVB2_ALIGNMENT_64K\n");
}
-
+
#else
if (VolumeHeader.Attributes & EFI_FVB2_READ_LOCK_CAP) {
@@ -769,140 +911,134 @@ Returns:
printf (" EFI_FVB2_WRITE_LOCK_STATUS\n");
}
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_1) {
+ switch (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT) {
+ case EFI_FVB2_ALIGNMENT_1:
printf (" EFI_FVB2_ALIGNMENT_1\n");
- }
-
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_2) {
- printf (" EFI_FVB2_ALIGNMENT_2\n");
- }
-
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_4) {
- printf (" EFI_FVB2_ALIGNMENT_4\n");
- }
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_8) {
- printf (" EFI_FVB2_ALIGNMENT_8\n");
- }
+ case EFI_FVB2_ALIGNMENT_2:
+ printf (" EFI_FVB2_ALIGNMENT_2\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_16) {
- printf (" EFI_FVB2_ALIGNMENT_16\n");
- }
+ case EFI_FVB2_ALIGNMENT_4:
+ printf (" EFI_FVB2_ALIGNMENT_4\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_32) {
- printf (" EFI_FVB2_ALIGNMENT_32\n");
- }
+ case EFI_FVB2_ALIGNMENT_8:
+ printf (" EFI_FVB2_ALIGNMENT_8\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_64) {
- printf (" EFI_FVB2_ALIGNMENT_64\n");
- }
+ case EFI_FVB2_ALIGNMENT_16:
+ printf (" EFI_FVB2_ALIGNMENT_16\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_128) {
- printf (" EFI_FVB2_ALIGNMENT_128\n");
- }
+ case EFI_FVB2_ALIGNMENT_32:
+ printf (" EFI_FVB2_ALIGNMENT_32\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_256) {
- printf (" EFI_FVB2_ALIGNMENT_256\n");
- }
+ case EFI_FVB2_ALIGNMENT_64:
+ printf (" EFI_FVB2_ALIGNMENT_64\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_512) {
- printf (" EFI_FVB2_ALIGNMENT_512\n");
- }
+ case EFI_FVB2_ALIGNMENT_128:
+ printf (" EFI_FVB2_ALIGNMENT_128\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_1K) {
- printf (" EFI_FVB2_ALIGNMENT_1K\n");
- }
+ case EFI_FVB2_ALIGNMENT_256:
+ printf (" EFI_FVB2_ALIGNMENT_256\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_2K) {
- printf (" EFI_FVB2_ALIGNMENT_2K\n");
- }
+ case EFI_FVB2_ALIGNMENT_512:
+ printf (" EFI_FVB2_ALIGNMENT_512\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_4K) {
- printf (" EFI_FVB2_ALIGNMENT_4K\n");
- }
+ case EFI_FVB2_ALIGNMENT_1K:
+ printf (" EFI_FVB2_ALIGNMENT_1K\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_8K) {
- printf (" EFI_FVB2_ALIGNMENT_8K\n");
- }
+ case EFI_FVB2_ALIGNMENT_2K:
+ printf (" EFI_FVB2_ALIGNMENT_2K\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_16K) {
- printf (" EFI_FVB2_ALIGNMENT_16K\n");
- }
+ case EFI_FVB2_ALIGNMENT_4K:
+ printf (" EFI_FVB2_ALIGNMENT_4K\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_32K) {
- printf (" EFI_FVB2_ALIGNMENT_32K\n");
- }
+ case EFI_FVB2_ALIGNMENT_8K:
+ printf (" EFI_FVB2_ALIGNMENT_8K\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_64K) {
- printf (" EFI_FVB2_ALIGNMENT_64K\n");
- }
+ case EFI_FVB2_ALIGNMENT_16K:
+ printf (" EFI_FVB2_ALIGNMENT_16K\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_128K) {
- printf (" EFI_FVB2_ALIGNMENT_128K\n");
- }
+ case EFI_FVB2_ALIGNMENT_32K:
+ printf (" EFI_FVB2_ALIGNMENT_32K\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_256K) {
- printf (" EFI_FVB2_ALIGNMENT_256K\n");
- }
+ case EFI_FVB2_ALIGNMENT_64K:
+ printf (" EFI_FVB2_ALIGNMENT_64K\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_512K) {
- printf (" EFI_FVB2_ALIGNMENT_512K\n");
- }
+ case EFI_FVB2_ALIGNMENT_128K:
+ printf (" EFI_FVB2_ALIGNMENT_128K\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_1M) {
- printf (" EFI_FVB2_ALIGNMENT_1M\n");
- }
+ case EFI_FVB2_ALIGNMENT_256K:
+ printf (" EFI_FVB2_ALIGNMENT_256K\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_2M) {
- printf (" EFI_FVB2_ALIGNMENT_2M\n");
- }
+ case EFI_FVB2_ALIGNMENT_512K:
+ printf (" EFI_FVB2_ALIGNMENT_512K\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_4M) {
- printf (" EFI_FVB2_ALIGNMENT_4M\n");
- }
+ case EFI_FVB2_ALIGNMENT_1M:
+ printf (" EFI_FVB2_ALIGNMENT_1M\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_8M) {
- printf (" EFI_FVB2_ALIGNMENT_8M\n");
- }
+ case EFI_FVB2_ALIGNMENT_2M:
+ printf (" EFI_FVB2_ALIGNMENT_2M\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_16M) {
- printf (" EFI_FVB2_ALIGNMENT_16M\n");
- }
+ case EFI_FVB2_ALIGNMENT_4M:
+ printf (" EFI_FVB2_ALIGNMENT_4M\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_32M) {
- printf (" EFI_FVB2_ALIGNMENT_32M\n");
- }
+ case EFI_FVB2_ALIGNMENT_8M:
+ printf (" EFI_FVB2_ALIGNMENT_8M\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_64M) {
- printf (" EFI_FVB2_ALIGNMENT_64M\n");
- }
+ case EFI_FVB2_ALIGNMENT_16M:
+ printf (" EFI_FVB2_ALIGNMENT_16M\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_128M) {
- printf (" EFI_FVB2_ALIGNMENT_128M\n");
- }
+ case EFI_FVB2_ALIGNMENT_32M:
+ printf (" EFI_FVB2_ALIGNMENT_32M\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_64M) {
- printf (" EFI_FVB2_ALIGNMENT_64M\n");
- }
+ case EFI_FVB2_ALIGNMENT_64M:
+ printf (" EFI_FVB2_ALIGNMENT_64M\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_128M) {
- printf (" EFI_FVB2_ALIGNMENT_128M\n");
- }
+ case EFI_FVB2_ALIGNMENT_128M:
+ printf (" EFI_FVB2_ALIGNMENT_128M\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_256M) {
- printf (" EFI_FVB2_ALIGNMENT_256M\n");
- }
+ case EFI_FVB2_ALIGNMENT_256M:
+ printf (" EFI_FVB2_ALIGNMENT_256M\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_512M) {
- printf (" EFI_FVB2_ALIGNMENT_512M\n");
- }
+ case EFI_FVB2_ALIGNMENT_512M:
+ printf (" EFI_FVB2_ALIGNMENT_512M\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_1G) {
- printf (" EFI_FVB2_ALIGNMENT_1G\n");
- }
+ case EFI_FVB2_ALIGNMENT_1G:
+ printf (" EFI_FVB2_ALIGNMENT_1G\n");
+ break;
- if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_2G) {
- printf (" EFI_FVB2_ALIGNMENT_2G\n");
+ case EFI_FVB2_ALIGNMENT_2G:
+ printf (" EFI_FVB2_ALIGNMENT_2G\n");
+ break;
}
#endif
@@ -915,7 +1051,10 @@ Returns:
printf ("Revision: 0x%04X\n", VolumeHeader.Revision);
do {
- fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);
+ ReadSize = fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);
+ if (ReadSize != 1) {
+ return EFI_ABORTED;
+ }
BytesRead += sizeof (EFI_FV_BLOCK_MAP_ENTRY);
if (BlockMap.NumBlocks != 0) {
@@ -932,7 +1071,7 @@ Returns:
}
if (VolumeHeader.FvLength != Size) {
- printf ("ERROR: Volume Size not consistant with Block Maps!\n");
+ printf ("ERROR: Volume Size not consistent with Block Maps!\n");
return EFI_ABORTED;
}
@@ -979,7 +1118,7 @@ Returns:
EFI_STATUS Status;
UINT8 GuidBuffer[PRINTED_GUID_BUFFER_SIZE];
UINT32 HeaderSize;
-#if (PI_SPECIFICATION_VERSION < 0x00010000)
+#if (PI_SPECIFICATION_VERSION < 0x00010000)
UINT16 *Tail;
#endif
//
@@ -1081,7 +1220,7 @@ Returns:
return EFI_ABORTED;
}
}
-#if (PI_SPECIFICATION_VERSION < 0x00010000)
+#if (PI_SPECIFICATION_VERSION < 0x00010000)
//
// Verify tail if present
//
@@ -1096,7 +1235,7 @@ Returns:
return EFI_ABORTED;
}
}
- #endif
+ #endif
break;
default:
@@ -1160,6 +1299,14 @@ Returns:
printf ("EFI_FV_FILETYPE_SMM_CORE\n");
break;
+ case EFI_FV_FILETYPE_MM_STANDALONE:
+ printf ("EFI_FV_FILETYPE_MM_STANDALONE\n");
+ break;
+
+ case EFI_FV_FILETYPE_MM_CORE_STANDALONE:
+ printf ("EFI_FV_FILETYPE_MM_CORE_STANDALONE\n");
+ break;
+
case EFI_FV_FILETYPE_FFS_PAD:
printf ("EFI_FV_FILETYPE_FFS_PAD\n");
break;
@@ -1197,6 +1344,280 @@ Returns:
return EFI_SUCCESS;
}
+EFI_STATUS
+RebaseImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINT32 *ReadSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
+
+Arguments:
+
+ FileHandle - The handle to the PE/COFF file
+
+ FileOffset - The offset, in bytes, into the file to read
+
+ ReadSize - The number of bytes to read from the file starting at FileOffset
+
+ Buffer - A pointer to the buffer to read the data into.
+
+Returns:
+
+ EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
+
+--*/
+{
+ CHAR8 *Destination8;
+ CHAR8 *Source8;
+ UINT32 Length;
+
+ Destination8 = Buffer;
+ Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
+ Length = *ReadSize;
+ while (Length--) {
+ *(Destination8++) = *(Source8++);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SetAddressToSectionHeader (
+ IN CHAR8 *FileName,
+ IN OUT UINT8 *FileBuffer,
+ IN UINT64 NewPe32BaseAddress
+ )
+/*++
+
+Routine Description:
+
+ Set new base address into the section header of PeImage
+
+Arguments:
+
+ FileName - Name of file
+ FileBuffer - Pointer to PeImage.
+ NewPe32BaseAddress - New Base Address for PE image.
+
+Returns:
+
+ EFI_SUCCESS Set new base address into this image successfully.
+
+--*/
+{
+ EFI_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ UINTN Index;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;
+
+ //
+ // Initialize context
+ //
+ memset (&ImageContext, 0, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *) FileBuffer;
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) RebaseImageRead;
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s is not valid", FileName);
+ return Status;
+ }
+
+ if (ImageContext.RelocationsStripped) {
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s has no relocation to be fixed up", FileName);
+ return Status;
+ }
+
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + ImageContext.PeCoffHeaderOffset);
+
+ //
+ // Get section header list
+ //
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
+ (UINTN) ImgHdr +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
+ );
+
+ //
+ // Set base address into the first section header that doesn't point to code section.
+ //
+ for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {
+ if ((SectionHeader->Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
+ *(UINT64 *) &SectionHeader->PointerToRelocations = NewPe32BaseAddress;
+ break;
+ }
+ }
+
+ //
+ // BaseAddress is set to section header.
+ //
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RebaseImage (
+ IN CHAR8 *FileName,
+ IN OUT UINT8 *FileBuffer,
+ IN UINT64 NewPe32BaseAddress
+ )
+/*++
+
+Routine Description:
+
+ Set new base address into PeImage, and fix up PeImage based on new address.
+
+Arguments:
+
+ FileName - Name of file
+ FileBuffer - Pointer to PeImage.
+ NewPe32BaseAddress - New Base Address for PE image.
+
+Returns:
+
+ EFI_INVALID_PARAMETER - BaseAddress is not valid.
+ EFI_SUCCESS - Update PeImage is correctly.
+
+--*/
+{
+ EFI_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ UINTN Index;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ UINT8 *MemoryImagePointer;
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;
+
+ //
+ // Initialize context
+ //
+ memset (&ImageContext, 0, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *) FileBuffer;
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) RebaseImageRead;
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s is not valid", FileName);
+ return Status;
+ }
+
+ if (ImageContext.RelocationsStripped) {
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s has no relocation to be fixed up", FileName);
+ return Status;
+ }
+
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + ImageContext.PeCoffHeaderOffset);
+
+ //
+ // Load and Relocate Image Data
+ //
+ MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
+ if (MemoryImagePointer == NULL) {
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
+ ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((INT64)ImageContext.SectionAlignment - 1));
+
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
+ free ((VOID *) MemoryImagePointer);
+ return Status;
+ }
+
+ ImageContext.DestinationAddress = NewPe32BaseAddress;
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);
+ free ((VOID *) MemoryImagePointer);
+ return Status;
+ }
+
+ //
+ // Copy Relocated data to raw image file.
+ //
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
+ (UINTN) ImgHdr +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
+ );
+
+ for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {
+ CopyMem (
+ FileBuffer + SectionHeader->PointerToRawData,
+ (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress),
+ SectionHeader->SizeOfRawData
+ );
+ }
+
+ free ((VOID *) MemoryImagePointer);
+
+ //
+ // Update Image Base Address
+ //
+ if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32) NewPe32BaseAddress;
+ } else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;
+ } else {
+ Error (NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
+ ImgHdr->Pe32.OptionalHeader.Magic,
+ FileName
+ );
+ return EFI_ABORTED;
+ }
+
+ //
+ // Set new base address into section header
+ //
+ Status = SetAddressToSectionHeader (FileName, FileBuffer, NewPe32BaseAddress);
+
+ return Status;
+}
+
+EFI_STATUS
+CombinePath (
+ IN CHAR8* DefaultPath,
+ IN CHAR8* AppendPath,
+ OUT CHAR8* NewPath
+)
+{
+ UINT32 DefaultPathLen;
+ UINT64 Index;
+ CHAR8 QuotesStr[] = "\"";
+ strcpy(NewPath, QuotesStr);
+ DefaultPathLen = strlen(DefaultPath);
+ strcat(NewPath, DefaultPath);
+ Index = 0;
+ for (; Index < DefaultPathLen + 1; Index ++) {
+ if (NewPath[Index] == '\\' || NewPath[Index] == '/') {
+ if (NewPath[Index + 1] != '\0') {
+ NewPath[Index] = '/';
+ }
+ }
+ }
+ if (NewPath[Index -1] != '/') {
+ NewPath[Index] = '/';
+ NewPath[Index + 1] = '\0';
+ }
+ strcat(NewPath, AppendPath);
+ strcat(NewPath, QuotesStr);
+ return EFI_SUCCESS;
+}
+
EFI_STATUS
ParseSection (
IN UINT8 *SectionBuffer,
@@ -1217,7 +1638,7 @@ Returns:
EFI_SECTION_ERROR - Problem with section parsing.
(a) compression errors
- (b) unrecognized section
+ (b) unrecognized section
EFI_UNSUPPORTED - Do not know how to parse the section.
EFI_SUCCESS - Section successfully parsed.
EFI_OUT_OF_RESOURCES - Memory allocation failed.
@@ -1247,14 +1668,20 @@ Returns:
CHAR8 *ExtractionTool;
CHAR8 *ToolInputFile;
CHAR8 *ToolOutputFile;
- CHAR8 *SystemCommandFormatString;
CHAR8 *SystemCommand;
EFI_GUID *EfiGuid;
UINT16 DataOffset;
UINT16 Attributes;
UINT32 RealHdrLen;
+ CHAR8 *ToolInputFileName;
+ CHAR8 *ToolOutputFileName;
+ CHAR8 *UIFileName;
+ CHAR8 *VersionString;
ParsedLength = 0;
+ ToolInputFileName = NULL;
+ ToolOutputFileName = NULL;
+
while (ParsedLength < BufferLength) {
Ptr = SectionBuffer + ParsedLength;
@@ -1278,21 +1705,94 @@ Returns:
SectionHeaderLen = GetSectionHeaderLength((EFI_COMMON_SECTION_HEADER *)Ptr);
SectionName = SectionNameToStr (Type);
- printf ("------------------------------------------------------------\n");
- printf (" Type: %s\n Size: 0x%08X\n", SectionName, (unsigned) SectionLength);
- free (SectionName);
+ if (SectionName != NULL) {
+ printf ("------------------------------------------------------------\n");
+ printf (" Type: %s\n Size: 0x%08X\n", SectionName, (unsigned) SectionLength);
+ free (SectionName);
+ }
switch (Type) {
case EFI_SECTION_RAW:
- case EFI_SECTION_PE32:
case EFI_SECTION_PIC:
case EFI_SECTION_TE:
// default is no more information
break;
+ case EFI_SECTION_PE32:
+ if (EnableHash) {
+ ToolInputFileName = "edk2Temp_InputEfi.tmp";
+ ToolOutputFileName = "edk2Temp_OutputHash.tmp";
+ RebaseImage(ToolInputFileName, (UINT8*)Ptr + SectionHeaderLen, 0);
+ PutFileImage (
+ ToolInputFileName,
+ (CHAR8*)Ptr + SectionHeaderLen,
+ SectionLength - SectionHeaderLen
+ );
+
+ SystemCommand = malloc (
+ strlen (OPENSSL_COMMAND_FORMAT_STRING) +
+ strlen (OpenSslPath) +
+ strlen (ToolInputFileName) +
+ strlen (ToolOutputFileName) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ OPENSSL_COMMAND_FORMAT_STRING,
+ OpenSslPath,
+ ToolOutputFileName,
+ ToolInputFileName
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ Error (NULL, 0, 3000, "Open SSL command not available. Please verify PATH or set OPENSSL_PATH.", NULL);
+ }
+ else {
+ FILE *fp;
+ CHAR8 *StrLine;
+ CHAR8 *NewStr;
+ UINT32 nFileLen;
+ if((fp = fopen(ToolOutputFileName,"r")) == NULL) {
+ Error (NULL, 0, 0004, "Hash the PE32 image failed.", NULL);
+ }
+ else {
+ fseek(fp,0,SEEK_SET);
+ fseek(fp,0,SEEK_END);
+ nFileLen = ftell(fp);
+ fseek(fp,0,SEEK_SET);
+ StrLine = malloc(nFileLen);
+ if (StrLine == NULL) {
+ fclose(fp);
+ free (SystemCommand);
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ fgets(StrLine, nFileLen, fp);
+ NewStr = strrchr (StrLine, '=');
+ printf (" SHA1: %s\n", NewStr + 1);
+ free (StrLine);
+ fclose(fp);
+ }
+ }
+ remove(ToolInputFileName);
+ remove(ToolOutputFileName);
+ free (SystemCommand);
+ }
+ break;
+
case EFI_SECTION_USER_INTERFACE:
- // name = &((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameString;
- // printf (" String: %s\n", &name);
+ UIFileName = (CHAR8 *) malloc (UnicodeStrLen (((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameString) + 1);
+ if (UIFileName == NULL) {
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Unicode2AsciiString (((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameString, UIFileName);
+ printf (" String: %s\n", UIFileName);
+ free (UIFileName);
break;
case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
@@ -1317,8 +1817,14 @@ Returns:
break;
case EFI_SECTION_VERSION:
- printf (" Build Number: 0x%02X\n", *(UINT16 *)(Ptr + SectionHeaderLen));
- printf (" Version Strg: %s\n", (char*) (Ptr + SectionHeaderLen + sizeof (UINT16)));
+ printf (" Build Number: 0x%04X\n", *(UINT16 *)(Ptr + SectionHeaderLen));
+ VersionString = (CHAR8 *) malloc (UnicodeStrLen (((EFI_VERSION_SECTION *) Ptr)->VersionString) + 1);
+ if (VersionString == NULL) {
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Unicode2AsciiString (((EFI_VERSION_SECTION *) Ptr)->VersionString, VersionString);
+ printf (" Version String: %s\n", VersionString);
break;
case EFI_SECTION_COMPRESSION:
@@ -1368,8 +1874,14 @@ Returns:
}
ScratchBuffer = malloc (ScratchSize);
+ if (ScratchBuffer == NULL) {
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
+ return EFI_OUT_OF_RESOURCES;
+ }
UncompressedBuffer = malloc (UncompressedLength);
- if ((ScratchBuffer == NULL) || (UncompressedBuffer == NULL)) {
+ if (UncompressedBuffer == NULL) {
+ free (ScratchBuffer);
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
return EFI_OUT_OF_RESOURCES;
}
Status = DecompressFunction (
@@ -1429,24 +1941,56 @@ Returns:
);
if (ExtractionTool != NULL) {
-
+ #ifndef __GNUC__
ToolInputFile = CloneString (tmpnam (NULL));
ToolOutputFile = CloneString (tmpnam (NULL));
+ #else
+ char tmp1[] = "/tmp/fileXXXXXX";
+ char tmp2[] = "/tmp/fileXXXXXX";
+ int fd1;
+ int fd2;
+ fd1 = mkstemp(tmp1);
+ fd2 = mkstemp(tmp2);
+ ToolInputFile = CloneString(tmp1);
+ ToolOutputFile = CloneString(tmp2);
+ close(fd1);
+ close(fd2);
+ #endif
+
+ if ((ToolInputFile == NULL) || (ToolOutputFile == NULL)) {
+ if (ToolInputFile != NULL) {
+ free (ToolInputFile);
+ }
+ if (ToolOutputFile != NULL) {
+ free (ToolOutputFile);
+ }
+ free (ExtractionTool);
+
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
+ return EFI_OUT_OF_RESOURCES;
+ }
//
// Construction 'system' command string
//
- SystemCommandFormatString = "%s -d -o %s %s";
SystemCommand = malloc (
- strlen (SystemCommandFormatString) +
+ strlen (EXTRACT_COMMAND_FORMAT_STRING) +
strlen (ExtractionTool) +
strlen (ToolInputFile) +
strlen (ToolOutputFile) +
1
);
+ if (SystemCommand == NULL) {
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ExtractionTool);
+
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
+ return EFI_OUT_OF_RESOURCES;
+ }
sprintf (
SystemCommand,
- SystemCommandFormatString,
+ EXTRACT_COMMAND_FORMAT_STRING,
ExtractionTool,
ToolOutputFile,
ToolInputFile
@@ -1472,6 +2016,7 @@ Returns:
);
remove (ToolOutputFile);
free (ToolOutputFile);
+ free (SystemCommand);
if (EFI_ERROR (Status)) {
Error (NULL, 0, 0004, "unable to read decoded GUIDED section", NULL);
return EFI_SECTION_ERROR;
@@ -1714,24 +2259,36 @@ Returns:
{
FILE *Fptr;
CHAR8 Line[MAX_LINE_LEN];
+ CHAR8 FormatString[MAX_LINE_LEN];
GUID_TO_BASENAME *GPtr;
- if ((Fptr = fopen (FileName, "r")) == NULL) {
+ if ((Fptr = fopen (LongFilePath (FileName), "r")) == NULL) {
printf ("ERROR: Failed to open input cross-reference file '%s'\n", FileName);
return EFI_DEVICE_ERROR;
}
+ //
+ // Generate the format string for fscanf
+ //
+ sprintf (
+ FormatString,
+ "%%%us %%%us",
+ (unsigned) sizeof (GPtr->Guid) - 1,
+ (unsigned) sizeof (GPtr->BaseName) - 1
+ );
+
while (fgets (Line, sizeof (Line), Fptr) != NULL) {
//
// Allocate space for another guid/basename element
//
GPtr = malloc (sizeof (GUID_TO_BASENAME));
if (GPtr == NULL) {
+ fclose (Fptr);
return EFI_OUT_OF_RESOURCES;
}
memset ((char *) GPtr, 0, sizeof (GUID_TO_BASENAME));
- if (sscanf (Line, "%s %s", GPtr->Guid, GPtr->BaseName) == 2) {
+ if (sscanf (Line, FormatString, GPtr->Guid, GPtr->BaseName) == 2) {
GPtr->Next = mGuidBaseNameList;
mGuidBaseNameList = GPtr;
} else {
@@ -1837,19 +2394,35 @@ Returns:
//
// Copyright declaration
- //
- fprintf (stdout, "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.\n\n");
+ //
+ fprintf (stdout, "Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.\n\n");
+ fprintf (stdout, " Display Tiano Firmware Volume FFS image information\n\n");
//
// Details Option
//
- fprintf (stdout, "Options:\n");
- fprintf (stdout, " -x xref, --xref xref\n\
- Parse basename to file-guid cross reference file(s).\n");
- fprintf (stdout, " --offset offset\n\
- Offset of file to start processing FV at.\n");
+ fprintf (stdout, "optional arguments:\n");
fprintf (stdout, " -h, --help\n\
- Show this help message and exit.\n");
-
+ Show this help message and exit\n");
+ fprintf (stdout, " --version\n\
+ Show program's version number and exit\n");
+ fprintf (stdout, " -d [DEBUG], --debug [DEBUG]\n\
+ Output DEBUG statements, where DEBUG_LEVEL is 0 (min) - 9 (max)\n");
+ fprintf (stdout, " -v, --verbose\n\
+ Print informational statements\n");
+ fprintf (stdout, " -q, --quiet\n\
+ Returns the exit code, error messages will be displayed\n");
+ fprintf (stdout, " -s, --silent\n\
+ Returns only the exit code; informational and error\n\
+ messages are not displayed\n");
+ fprintf (stdout, " -x XREF_FILENAME, --xref XREF_FILENAME\n\
+ Parse the basename to file-guid cross reference file(s)\n");
+ fprintf (stdout, " -f OFFSET, --offset OFFSET\n\
+ The offset from the start of the input file to start \n\
+ processing an FV\n");
+ fprintf (stdout, " --hash\n\
+ Generate HASH value of the entire PE image\n");
+ fprintf (stdout, " --sfo\n\
+ Reserved for future use\n");
}