## @file
# Routines for generating build report.
#
# This module contains the functionality to generate build report after
# build all target completes successfully.
#
# Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
# 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
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
## Import Modules
#
import os
import re
import platform
import textwrap
import traceback
import sys
import time
import struct
## Pattern to extract contents in EDK DXS files
## Pattern to find total FV total size, occupied size in flash report intermediate file
## Pattern to find module size and time stamp in module summary report intermediate file
## Pattern to find GUID value in flash description files
## Pattern to collect offset, GUID value pair in the flash report intermediate file
## Pattern to find module base address and entry point in fixed flash map file
gModulePattern = r"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
## Pattern to find all module referenced header files in source files
## Pattern to find the entry point for EDK module using EDKII Glue library
## Tags for MaxLength of line in report
## Tags for section start, end and separator
## Tags for subsection start, end and separator
## The look up table to map PCD type to pair of report display type and DEC type
gPcdTypeMap = {
'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),
'PatchableInModule': ('PATCH', 'PatchableInModule'),
'FeatureFlag' : ('FLAG', 'FeatureFlag'),
'Dynamic' : ('DYN', 'Dynamic'),
'DynamicHii' : ('DYNHII', 'Dynamic'),
'DynamicVpd' : ('DYNVPD', 'Dynamic'),
'DynamicEx' : ('DEX', 'Dynamic'),
'DynamicExHii' : ('DEXHII', 'Dynamic'),
'DynamicExVpd' : ('DEXVPD', 'Dynamic'),
}
## The look up table to map module type to driver type
gDriverTypeMap = {
'SEC' : '0x3 (SECURITY_CORE)',
'PEI_CORE' : '0x4 (PEI_CORE)',
'PEIM' : '0x6 (PEIM)',
'DXE_CORE' : '0x5 (DXE_CORE)',
'DXE_DRIVER' : '0x7 (DRIVER)',
'DXE_SAL_DRIVER' : '0x7 (DRIVER)',
'DXE_SMM_DRIVER' : '0x7 (DRIVER)',
'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',
'UEFI_DRIVER' : '0x7 (DRIVER)',
'UEFI_APPLICATION' : '0x9 (APPLICATION)',
'SMM_CORE' : '0xD (SMM_CORE)',
'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
}
## The look up table of the supported opcode in the dependency expression binaries
##
# Writes a string to the file object.
#
# This function writes a string to the file object and a new line is appended
# afterwards. It may optionally wraps the string for better readability.
#
# @File The file object to write
# @String The string to be written to the file
# @Wrapper Indicates whether to wrap the string
#
if Wrapper:
##
# Find all the header file that the module source directly includes.
#
# This function scans source code to find all header files the module may
# include. This is not accurate but very effective to find all the header
# file the module might include with #include statement.
#
# @Source The source file name
# @IncludePathList The list of include path to find the source file.
# @IncludeFiles The dictionary of current found include files.
#
#
# Find header files with pattern #include "XXX.h" or #include <XXX.h>
#
break
#
# Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
#
if "ARCH_PROTOCOL" in Type:
elif "PROTOCOL" in Type:
elif "PPI" in Type:
elif "GUID" in Type:
else:
continue
for Dir in IncludePathList:
break
## Split each lines in file
#
# This method is used to split the lines in file to make the length of each line
# less than MaxLength.
#
# @param Content The content of file
# @param MaxLength The Max Length of the line
#
NewContent = ''
NewContentList = []
for Line in ContentList:
else:
if Line:
for NewLine in NewContentList:
return NewContent
##
# Parse binary dependency expression section
#
# This utility class parses the dependency expression section and translate the readable
# GUID name and value.
#
##
# Constructor function for class DepexParser
#
# This constructor function collect GUID values so that the readable
# GUID name can be translated.
#
# @param self The object pointer
# @param Wa Workspace context information
#
##
# Parse the binary dependency expression files.
#
# This function parses the binary dependency expression file and translate it
# to the instruction list.
#
# @param self The object pointer
# @param DepexFileName The file name of binary dependency expression file.
#
DepexStatement = []
while OpCode:
GuidValue = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
return DepexStatement
##
# Reports library information
#
# This class reports the module library subsection in the build report file.
#
##
# Constructor function for class LibraryReport
#
# This constructor function generates LibraryReport object for
# a module.
#
# @param self The object pointer
# @param M Module context information
#
self.LibraryList = []
else:
for Lib in M.DependentLibraryList:
self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList))
##
# Generate report for module library information
#
# This function generates report for the module library.
# If the module is EDKII style one, the additional library class, library
# constructor/destructor and dependency expression may also be reported.
#
# @param self The object pointer
# @param File The file object for report
#
#
# Report library class, library constructor and destructor for
# EDKII style module.
#
if self._EdkIIModule:
EdkIILibInfo = ""
if LibConstructor:
if LibDestructor:
if LibDepex:
if EdkIILibInfo:
else:
##
# Reports dependency expression information
#
# This class reports the module dependency expression subsection in the build report file.
#
##
# Constructor function for class DepexReport
#
# This constructor function generates DepexReport object for
# a module. If the module source contains the DXS file (usually EDK
# style module), it uses the dependency in DXS file; otherwise,
# it uses the dependency expression from its own INF [Depex] section
# and then merges with the ones from its dependent library INF.
#
# @param self The object pointer
# @param M Module context information
#
ModuleType = M.ModuleType
if not ModuleType:
return
for Source in M.SourceFileList:
if Match:
break
else:
if not self.ModuleDepex:
LibDepexList = []
for Lib in M.DependentLibraryList:
if LibDepex != "":
if not self.LibraryDepex:
##
# Generate report for module dependency expression information
#
# This function generates report for the module dependency expression.
#
# @param self The object pointer
# @param File The file object for report
# @param GlobalDepexParser The platform global Dependency expression parser object
#
return
try:
for DepexStatement in DepexStatements:
except:
else:
##
# Reports dependency expression information
#
# This class reports the module build flags subsection in the build report file.
#
##
# Constructor function for class BuildFlagsReport
#
# This constructor function generates BuildFlagsReport object for
# a module. It reports the build tool chain tag and all relevant
# build flags to build the module.
#
# @param self The object pointer
# @param M Module context information
#
BuildOptions = {}
#
# Add build flags according to source file extension so that
# irrelevant ones can be filtered out.
#
for Source in M.SourceFileList:
elif Ext in [".vfr"]:
elif Ext in [".dxs"]:
elif Ext in [".asl"]:
elif Ext in [".aslc"]:
elif Ext in [".asm16"]:
#
# Save module build flags.
#
self.BuildFlags = {}
for Tool in BuildOptions:
##
# Generate report for module build flags information
#
# This function generates report for the module build flags expression.
#
# @param self The object pointer
# @param File The file object for report
#
##
# Reports individual module information
#
# This class reports the module section in the build report file.
# It comprises of module summary, module PCD, library, dependency expression,
# build flags sections.
#
##
# Constructor function for class ModuleReport
#
# This constructor function generates ModuleReport object for
# a separate module in a platform build.
#
# @param self The object pointer
# @param M Module context information
# @param ReportType The kind of report items in the final report file
#
self.BuildTimeStamp = None
if not M.IsLibrary:
ModuleType = M.ModuleType
if not ModuleType:
#
# If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
#
if ModuleType == "DXE_SMM_DRIVER":
ModuleType = "SMM_DRIVER"
self.ModulePcdSet = {}
if "PCD" in ReportType:
#
# Collect all module used PCD set: module INF referenced directly or indirectly.
# It also saves module INF default values of them in case they exist.
#
self.ModulePcdSet.setdefault((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Type), (Pcd.InfDefaultValue, Pcd.DefaultValue))
self.LibraryReport = None
if "LIBRARY" in ReportType:
self.DepexReport = None
if "DEPEX" in ReportType:
if "BUILD_FLAGS" in ReportType:
##
# Generate report for module information
#
# This function generates report for separate module expression
# in a platform build.
#
# @param self The object pointer
# @param File The file object for report
# @param GlobalPcdReport The platform global PCD report object
# @param GlobalPredictionReport The platform global Prediction report object
# @param GlobalDepexParser The platform global Dependency expression parser object
# @param ReportType The kind of report items in the final report file
#
def GenerateReport(self, File, GlobalPcdReport, GlobalPredictionReport, GlobalDepexParser, ReportType):
try:
if Match:
if Match:
except IOError:
if self.BuildTimeStamp:
if self.DriverType:
if self.UefiSpecVersion:
if self.PiSpecVersion:
if self.PciDeviceId:
if self.PciVendorId:
if self.PciClassCode:
if "PCD" in ReportType:
if "LIBRARY" in ReportType:
if "DEPEX" in ReportType:
if "BUILD_FLAGS" in ReportType:
##
# Reports platform and module PCD information
#
# This class reports the platform PCD section and module PCD subsection
# in the build report file.
#
##
# Constructor function for class PcdReport
#
# This constructor function generates PcdReport object a platform build.
# It collects the whole PCD database from platform DSC files, platform
# flash description file and package DEC files.
#
# @param self The object pointer
# @param Wa Workspace context information
#
if Wa.FdfProfile:
else:
self.ModulePcdOverride = {}
#
# Collect all platform referenced PCDs and grouped them by PCD token space
# GUID C Names
#
#
# Collect module override PCDs
#
#
# Collect PCD DEC default value.
#
self.DecPcdDefault = {}
#
# Collect PCDs defined in DSC common section
#
self.DscPcdDefault = {}
if DscDefaultValue:
##
# Generate report for PCD information
#
# This function generates report for separate module expression
# in a platform build.
#
# @param self The object pointer
# @param File The file object for report
# @param ModulePcdSet Set of all PCDs referenced by module or None for
# platform PCD report
# @param DscOverridePcds Module DSC override PCDs set
#
if ModulePcdSet == None:
#
# For platform global PCD section
#
else:
#
# For module PCD sub-section
#
#
# Group PCD by their token space GUID C Name
#
#
# Group PCD by their usage type
#
#
# Get PCD default value and their override relationship
#
InfDefaultValue = None
if DscDefaultValue:
if ModulePcdSet != None:
continue
if InfDefault == "":
InfDefault = None
if First:
if ModulePcdSet == None:
if DecDefaultValue == None:
else:
if InfDefaultValue == None:
else:
if DscDefaultValue == None:
else:
else:
if DecDefaultValue == None:
else:
if InfDefaultValue == None:
else:
if DscDefaultValue == None:
else:
#
# Report PCD item according to their override relationship
#
FileWrite(File, ' %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))
else:
if DscMatch:
FileWrite(File, ' *F %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))
else:
FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))
else:
FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))
FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset))
else:
if not DscMatch and DscDefaultValue != None:
if not InfMatch and InfDefaultValue != None:
if not DecMatch and DecDefaultValue != None:
if ModulePcdSet == None:
for ModulePath in ModuleOverride:
else:
if Match:
continue
if ModulePcdSet == None:
else:
##
# Reports platform and module Prediction information
#
# This class reports the platform execution order prediction section and
# module load fixed address prediction subsection in the build report file.
#
##
# Constructor function for class PredictionReport
#
# This constructor function generates PredictionReport object for the platform.
#
# @param self: The object pointer
# @param Wa Workspace context information
#
self._FfsEntryPoint = {}
self._SourceList = []
self.FixedMapDict = {}
#
# Collect all platform reference source files and GUID C Name
#
#
# BASE typed modules are EFI agnostic, so we need not scan
# information.
#
continue
#
# Add module referenced source files
#
IncludeList = {}
RealEntryPoint = "_ModuleEntryPoint"
else:
if EntryPoint == "_ModuleEntryPoint":
if Match:
#
# Collect platform firmware volume list as the input of EOT.
#
if Wa.FdfProfile:
continue
continue
try:
continue
except AttributeError:
pass
##
# Parse platform fixed address map files
#
# This function parses the platform final fixed address map file to get
# the database of predicted fixed address for module image base, entry point
# etc.
#
# @param self: The object pointer
#
if self._MapFileParsed:
return
try:
except:
##
# Invokes EOT tool to get the predicted the execution order.
#
# This function invokes EOT tool to calculate the predicted dispatch order
#
# @param self: The object pointer
#
if self._EotToolInvoked:
return
FvFileList = []
return
#
# Write source file list and GUID file list to an intermediate file
# as the input for EOT tool and dispatch List as the output file
# from EOT tool.
#
try:
#
# Invoke EOT tool and echo its runtime performance
#
#
# Parse the output of EOT tool
#
continue
except:
EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))
EdkLogger.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
##
# Generate platform execution order report
#
# This function generates the predicted module execution order.
#
# @param self The object pointer
# @param File The file object for report
#
return
##
# Generate Fixed Address report.
#
# This function generate the predicted fixed address report for a module
# specified by Guid.
#
# @param self The object pointer
# @param File The file object for report
# @param Guid The module Guid value.
# @param NotifyList The list of all notify function in a module
#
if not FixedAddressList:
return
for Item in FixedAddressList:
if Symbol == "*I":
Name = "(Image Base)"
elif Symbol == "*E":
elif Symbol in NotifyList:
Symbol = "*N"
else:
continue
if "Flash" in Type:
Symbol += "F"
elif "Memory" in Type:
Symbol += "M"
else:
Symbol += "S"
##
# Generate report for the prediction part
#
# This function generate the predicted fixed address report for a module or
# predicted module execution order for a platform.
# If the input Guid is None, then, it generates the predicted module execution order;
# otherwise it generated the module fixed loading address for the module specified by
# Guid.
#
# @param self The object pointer
# @param File The file object for report
# @param Guid The module Guid value.
#
if Guid:
else:
##
# Reports FD region information
#
# This class reports the FD subsection in the build report file.
# It collects region information of platform flash device.
# If the region is a firmware volume, it lists the set of modules
# and its space information; otherwise, it only lists its region name,
# base address and size in its sub-section header.
# If there are nesting FVs, the nested FVs will list immediate after
# this FD region subsection
#
##
# Discover all the nested FV name list.
#
# This is an internal worker function to discover the all the nested FV information
# in the parent firmware volume. It uses deep first search algorithm recursively to
# find all the FV list name and append them to the list.
#
# @param self The object pointer
# @param FvName The name of current firmware file system
# @param Wa Workspace context information
#
try:
continue
except AttributeError:
pass
##
# Constructor function for class FdRegionReport
#
# This constructor function generates FdRegionReport object for a specified FdRegion.
# If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
# volume list. This function also collects GUID map in order to dump module identification
# in the final report.
#
# @param self: The object pointer
# @param FdRegion The current FdRegion object
# @param Wa Workspace context information
#
#
# If the input FdRegion is not a firmware volume,
# we are done.
#
return
#
# Find all nested FVs in the FdRegion
#
continue
PlatformPcds = {}
#
# Collect PCDs declared in DEC files.
#
#
# Collect PCDs defined in DSC common section
#
#
# Add PEI and DXE a priori files GUIDs defined in PI specification.
#
#
# Add ACPI table storage file
#
#
# Collect the GUID map in the FV firmware volume
#
try:
#
# collect GUID map for binary EFI file in FDF file.
#
if Match:
try:
except AttributeError:
pass
except AttributeError:
pass
##
# Internal worker function to generate report for the FD region
#
# This internal worker function to generate report for the FD region.
# It the type is firmware volume, it lists offset and module identification.
#
# @param self The object pointer
# @param File The file object for report
# @param Title The title for the FD subsection
# @param BaseAddress The base address for the FD region
# @param Size The size of the FD region
# @param FvName The FV name if the FD region is a firmware volume
#
FvTotalSize = 0
FvTakenSize = 0
FvFreeSize = 0
try:
#
# Collect size info in the firmware volume.
#
if Match:
if Match:
#
# Write size information to the report file.
#
#
# Write module offset and module identification to the report file.
#
OffsetInfo = {}
for Offset in OffsetList:
except IOError:
else:
##
# Generate report for the FD region
#
# This function generates report for the FD region.
#
# @param self The object pointer
# @param File The file object for report
#
else:
##
# Reports FD information
#
# This class reports the FD section in the build report file.
# It collects flash device information for a platform.
#
##
# Constructor function for class FdReport
#
# This constructor function generates FdReport object for a specified
# firmware device.
#
# @param self The object pointer
# @param Fd The current Firmware device object
# @param Wa Workspace context information
#
##
# Generate report for the firmware device.
#
# This function generates report for the firmware device.
#
# @param self The object pointer
# @param File The file object for report
#
##
# Reports platform information
#
# This class reports the whole platform information
#
##
# Constructor function for class PlatformReport
#
# This constructor function generates PlatformReport object a platform build.
# It generates report for platform summary, flash, global PCDs and detailed
# module information for modules involved in platform build.
#
# @param self The object pointer
# @param Wa Workspace context information
# @param MaList The list of modules in the platform build
#
if "PCD" in ReportType:
self.FdReportList = []
self.PredictionReport = None
self.DepexParser = None
if "DEPEX" in ReportType:
self.ModuleReportList = []
if MaList != None:
else:
##
# Generate report for the whole platform.
#
# This function generates report for platform information.
# It comprises of platform summary, global PCD, flash and
# module list sections.
#
# @param self The object pointer
# @param File The file object for report
# @param BuildDuration The total time to build the modules
# @param ReportType The kind of report items in the final report file
#
if not self._IsModuleBuild:
if "PCD" in ReportType:
if "FLASH" in ReportType:
ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, self.DepexParser, ReportType)
if not self._IsModuleBuild:
if "EXECUTION_ORDER" in ReportType:
## BuildReport class
#
# This base class contain the routines to collect data and then
# applies certain format to the output report
#
##
# Constructor function for class BuildReport
#
# This constructor function generates BuildReport object a platform build.
# It generates report for platform summary, flash, global PCDs and detailed
# module information for modules involved in platform build.
#
# @param self The object pointer
# @param ReportFile The file name to save report file
# @param ReportType The kind of report items in the final report file
#
if ReportFile:
self.ReportList = []
self.ReportType = []
if ReportType:
for ReportTypeItem in ReportType:
else:
##
# Adds platform report to the list
#
# This function adds a platform report to the final report list.
#
# @param self The object pointer
# @param Wa Workspace context information
# @param MaList The list of modules in the platform build
#
if self.ReportFile:
##
# Generates the final report.
#
# This function generates platform build report. It invokes GenerateReport()
# method for every platform report in the list.
#
# @param self The object pointer
# @param BuildDuration The total time to build the modules
#
if self.ReportFile:
try:
except IOError:
except:
EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report", ExtraData=self.ReportFile, RaiseError=False)
EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))
# This acts like the main() function for the script, unless it is 'import'ed into another script.
if __name__ == '__main__':
pass