summaryrefslogtreecommitdiff
path: root/BaseTools/Source/Python/build/BuildReport.py
diff options
context:
space:
mode:
Diffstat (limited to 'BaseTools/Source/Python/build/BuildReport.py')
-rw-r--r--BaseTools/Source/Python/build/BuildReport.py4914
1 files changed, 2457 insertions, 2457 deletions
diff --git a/BaseTools/Source/Python/build/BuildReport.py b/BaseTools/Source/Python/build/BuildReport.py
index 26dfe53fff..b550124582 100644
--- a/BaseTools/Source/Python/build/BuildReport.py
+++ b/BaseTools/Source/Python/build/BuildReport.py
@@ -1,2457 +1,2457 @@
-## @file
-# Routines for generating build report.
-#
-# This module contains the functionality to generate build report after
-# build all target completes successfully.
-#
-# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-## Import Modules
-#
-import json
-from pathlib import Path
-import Common.LongFilePathOs as os
-import re
-import platform
-import textwrap
-import traceback
-import sys
-import time
-import struct
-import hashlib
-import subprocess
-import threading
-from datetime import datetime
-from io import BytesIO
-from Common import EdkLogger
-from Common.Misc import SaveFileOnChange
-from Common.Misc import GuidStructureByteArrayToGuidString
-from Common.Misc import GuidStructureStringToGuidString
-from Common.BuildToolError import FILE_WRITE_FAILURE
-from Common.BuildToolError import CODE_ERROR
-from Common.BuildToolError import COMMAND_FAILURE
-from Common.BuildToolError import FORMAT_INVALID
-from Common.LongFilePathSupport import OpenLongFilePath as open
-from Common.MultipleWorkspace import MultipleWorkspace as mws
-import Common.GlobalData as GlobalData
-from AutoGen.ModuleAutoGen import ModuleAutoGen
-from Common.Misc import PathClass
-from Common.StringUtils import NormPath
-from Common.DataType import *
-import collections
-from Common.Expression import *
-from GenFds.AprioriSection import DXE_APRIORI_GUID, PEI_APRIORI_GUID
-from AutoGen.IncludesAutoGen import IncludesAutoGen
-
-## Pattern to extract contents in EDK DXS files
-gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)
-
-## Pattern to find total FV total size, occupied size in flash report intermediate file
-gFvTotalSizePattern = re.compile(r"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
-gFvTakenSizePattern = re.compile(r"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
-
-## Pattern to find module size and time stamp in module summary report intermediate file
-gModuleSizePattern = re.compile(r"MODULE_SIZE = (\d+)")
-gTimeStampPattern = re.compile(r"TIME_STAMP = (\d+)")
-
-## Pattern to find GUID value in flash description files
-gPcdGuidPattern = re.compile(r"PCD\((\w+)[.](\w+)\)")
-
-## Pattern to collect offset, GUID value pair in the flash report intermediate file
-gOffsetGuidPattern = re.compile(r"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
-
-## 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*Type=\w+\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
-gMapFileItemPattern = re.compile(gModulePattern % {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
-
-## Pattern to find all module referenced header files in source files
-gIncludePattern = re.compile(r'#include\s*["<]([^">]+)[">]')
-gIncludePattern2 = re.compile(r"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
-
-## Pattern to find the entry point for EDK module using EDKII Glue library
-gGlueLibEntryPoint = re.compile(r"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
-
-## Tags for MaxLength of line in report
-gLineMaxLength = 120
-
-## Tags for end of line in report
-gEndOfLine = "\r\n"
-
-## Tags for section start, end and separator
-gSectionStart = ">" + "=" * (gLineMaxLength - 2) + "<"
-gSectionEnd = "<" + "=" * (gLineMaxLength - 2) + ">" + "\n"
-gSectionSep = "=" * gLineMaxLength
-
-## Tags for subsection start, end and separator
-gSubSectionStart = ">" + "-" * (gLineMaxLength - 2) + "<"
-gSubSectionEnd = "<" + "-" * (gLineMaxLength - 2) + ">"
-gSubSectionSep = "-" * gLineMaxLength
-
-
-## The look up table to map PCD type to pair of report display type and DEC type
-gPcdTypeMap = {
- TAB_PCDS_FIXED_AT_BUILD : ('FIXED', TAB_PCDS_FIXED_AT_BUILD),
- TAB_PCDS_PATCHABLE_IN_MODULE: ('PATCH', TAB_PCDS_PATCHABLE_IN_MODULE),
- TAB_PCDS_FEATURE_FLAG : ('FLAG', TAB_PCDS_FEATURE_FLAG),
- TAB_PCDS_DYNAMIC : ('DYN', TAB_PCDS_DYNAMIC),
- TAB_PCDS_DYNAMIC_HII : ('DYNHII', TAB_PCDS_DYNAMIC),
- TAB_PCDS_DYNAMIC_VPD : ('DYNVPD', TAB_PCDS_DYNAMIC),
- TAB_PCDS_DYNAMIC_EX : ('DEX', TAB_PCDS_DYNAMIC_EX),
- TAB_PCDS_DYNAMIC_EX_HII : ('DEXHII', TAB_PCDS_DYNAMIC_EX),
- TAB_PCDS_DYNAMIC_EX_VPD : ('DEXVPD', TAB_PCDS_DYNAMIC_EX),
- }
-
-## The look up table to map module type to driver type
-gDriverTypeMap = {
- SUP_MODULE_SEC : '0x3 (SECURITY_CORE)',
- SUP_MODULE_PEI_CORE : '0x4 (PEI_CORE)',
- SUP_MODULE_PEIM : '0x6 (PEIM)',
- SUP_MODULE_DXE_CORE : '0x5 (DXE_CORE)',
- SUP_MODULE_DXE_DRIVER : '0x7 (DRIVER)',
- SUP_MODULE_DXE_SAL_DRIVER : '0x7 (DRIVER)',
- SUP_MODULE_DXE_SMM_DRIVER : '0x7 (DRIVER)',
- SUP_MODULE_DXE_RUNTIME_DRIVER: '0x7 (DRIVER)',
- SUP_MODULE_UEFI_DRIVER : '0x7 (DRIVER)',
- SUP_MODULE_UEFI_APPLICATION : '0x9 (APPLICATION)',
- SUP_MODULE_SMM_CORE : '0xD (SMM_CORE)',
- 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
- SUP_MODULE_MM_STANDALONE : '0xE (MM_STANDALONE)',
- SUP_MODULE_MM_CORE_STANDALONE : '0xF (MM_CORE_STANDALONE)'
- }
-
-## The look up table of the supported opcode in the dependency expression binaries
-gOpCodeList = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
-
-## Save VPD Pcd
-VPDPcdList = []
-
-##
-# 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
-#
-def FileWrite(File, String, Wrapper=False):
- if Wrapper:
- String = textwrap.fill(String, 120)
- File.append(String + gEndOfLine)
-
-def ByteArrayForamt(Value):
- IsByteArray = False
- SplitNum = 16
- ArrayList = []
- if Value.startswith('{') and Value.endswith('}') and not Value.startswith("{CODE("):
- Value = Value[1:-1]
- ValueList = Value.split(',')
- if len(ValueList) >= SplitNum:
- IsByteArray = True
- if IsByteArray:
- if ValueList:
- Len = len(ValueList)/SplitNum
- for i, element in enumerate(ValueList):
- ValueList[i] = '0x%02X' % int(element.strip(), 16)
- if Len:
- Id = 0
- while (Id <= Len):
- End = min(SplitNum*(Id+1), len(ValueList))
- Str = ','.join(ValueList[SplitNum*Id : End])
- if End == len(ValueList):
- Str += '}'
- ArrayList.append(Str)
- break
- else:
- Str += ','
- ArrayList.append(Str)
- Id += 1
- else:
- ArrayList = [Value + '}']
- return IsByteArray, ArrayList
-
-##
-# 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.
-#
-def FindIncludeFiles(Source, IncludePathList, IncludeFiles):
- FileContents = open(Source).read()
- #
- # Find header files with pattern #include "XXX.h" or #include <XXX.h>
- #
- for Match in gIncludePattern.finditer(FileContents):
- FileName = Match.group(1).strip()
- for Dir in [os.path.dirname(Source)] + IncludePathList:
- FullFileName = os.path.normpath(os.path.join(Dir, FileName))
- if os.path.exists(FullFileName):
- IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName
- break
-
- #
- # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
- #
- for Match in gIncludePattern2.finditer(FileContents):
- Key = Match.group(2)
- Type = Match.group(1)
- if "ARCH_PROTOCOL" in Type:
- FileName = "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key}
- elif "PROTOCOL" in Type:
- FileName = "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key}
- elif "PPI" in Type:
- FileName = "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key}
- elif TAB_GUID in Type:
- FileName = "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key}
- else:
- continue
- for Dir in IncludePathList:
- FullFileName = os.path.normpath(os.path.join(Dir, FileName))
- if os.path.exists(FullFileName):
- IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName
- 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
-#
-def FileLinesSplit(Content=None, MaxLength=None):
- ContentList = Content.split(TAB_LINE_BREAK)
- NewContent = ''
- NewContentList = []
- for Line in ContentList:
- while len(Line.rstrip()) > MaxLength:
- LineSpaceIndex = Line.rfind(TAB_SPACE_SPLIT, 0, MaxLength)
- LineSlashIndex = Line.rfind(TAB_SLASH, 0, MaxLength)
- LineBackSlashIndex = Line.rfind(TAB_BACK_SLASH, 0, MaxLength)
- if max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex) > 0:
- LineBreakIndex = max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex)
- else:
- LineBreakIndex = MaxLength
- NewContentList.append(Line[:LineBreakIndex])
- Line = Line[LineBreakIndex:]
- if Line:
- NewContentList.append(Line)
- for NewLine in NewContentList:
- NewContent += NewLine + TAB_LINE_BREAK
-
- NewContent = NewContent.replace(gEndOfLine, TAB_LINE_BREAK).replace('\r\r\n', gEndOfLine)
- return NewContent
-
-
-
-##
-# Parse binary dependency expression section
-#
-# This utility class parses the dependency expression section and translate the readable
-# GUID name and value.
-#
-class DepexParser(object):
- ##
- # 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
- #
- def __init__(self, Wa):
- self._GuidDb = {}
- for Pa in Wa.AutoGenObjectList:
- for Package in Pa.PackageList:
- for Protocol in Package.Protocols:
- GuidValue = GuidStructureStringToGuidString(Package.Protocols[Protocol])
- self._GuidDb[GuidValue.upper()] = Protocol
- for Ppi in Package.Ppis:
- GuidValue = GuidStructureStringToGuidString(Package.Ppis[Ppi])
- self._GuidDb[GuidValue.upper()] = Ppi
- for Guid in Package.Guids:
- GuidValue = GuidStructureStringToGuidString(Package.Guids[Guid])
- self._GuidDb[GuidValue.upper()] = Guid
- for Ma in Pa.ModuleAutoGenList:
- for Pcd in Ma.FixedVoidTypePcds:
- PcdValue = Ma.FixedVoidTypePcds[Pcd]
- if len(PcdValue.split(',')) == 16:
- GuidValue = GuidStructureByteArrayToGuidString(PcdValue)
- self._GuidDb[GuidValue.upper()] = Pcd
- ##
- # 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.
- #
- def ParseDepexFile(self, DepexFileName):
- DepexFile = open(DepexFileName, "rb")
- DepexStatement = []
- OpCode = DepexFile.read(1)
- while OpCode:
- Statement = gOpCodeList[struct.unpack("B", OpCode)[0]]
- if Statement in ["BEFORE", "AFTER", "PUSH"]:
- GuidValue = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
- struct.unpack(PACK_PATTERN_GUID, DepexFile.read(16))
- GuidString = self._GuidDb.get(GuidValue, GuidValue)
- Statement = "%s %s" % (Statement, GuidString)
- DepexStatement.append(Statement)
- OpCode = DepexFile.read(1)
-
- return DepexStatement
-
-##
-# Reports library information
-#
-# This class reports the module library subsection in the build report file.
-#
-class LibraryReport(object):
- ##
- # Constructor function for class LibraryReport
- #
- # This constructor function generates LibraryReport object for
- # a module.
- #
- # @param self The object pointer
- # @param M Module context information
- #
- def __init__(self, M):
- self.LibraryList = []
-
- for Lib in M.DependentLibraryList:
- LibInfPath = str(Lib)
- LibClassList = Lib.LibraryClass[0].LibraryClass
- LibConstructorList = Lib.ConstructorList
- LibDesstructorList = Lib.DestructorList
- LibDepexList = Lib.DepexExpression[M.Arch, M.ModuleType]
- for LibAutoGen in M.LibraryAutoGenList:
- if LibInfPath == LibAutoGen.MetaFile.Path:
- LibTime = LibAutoGen.BuildTime
- break
- self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList, LibTime))
-
- ##
- # 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
- #
- def GenerateReport(self, File):
- if len(self.LibraryList) > 0:
- FileWrite(File, gSubSectionStart)
- FileWrite(File, TAB_BRG_LIBRARY)
- FileWrite(File, gSubSectionSep)
- for LibraryItem in self.LibraryList:
- LibInfPath = LibraryItem[0]
- FileWrite(File, LibInfPath)
-
- LibClass = LibraryItem[1]
- EdkIILibInfo = ""
- LibConstructor = " ".join(LibraryItem[2])
- if LibConstructor:
- EdkIILibInfo += " C = " + LibConstructor
- LibDestructor = " ".join(LibraryItem[3])
- if LibDestructor:
- EdkIILibInfo += " D = " + LibDestructor
- LibDepex = " ".join(LibraryItem[4])
- if LibDepex:
- EdkIILibInfo += " Depex = " + LibDepex
- if LibraryItem[5]:
- EdkIILibInfo += " Time = " + LibraryItem[5]
- if EdkIILibInfo:
- FileWrite(File, "{%s: %s}" % (LibClass, EdkIILibInfo))
- else:
- FileWrite(File, "{%s}" % LibClass)
-
- FileWrite(File, gSubSectionEnd)
-
-##
-# Reports dependency expression information
-#
-# This class reports the module dependency expression subsection in the build report file.
-#
-class DepexReport(object):
- ##
- # 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
- #
- def __init__(self, M):
- self.Depex = ""
- self._DepexFileName = os.path.join(M.BuildDir, "OUTPUT", M.Module.BaseName + ".depex")
- ModuleType = M.ModuleType
- if not ModuleType:
- ModuleType = COMPONENT_TO_MODULE_MAP_DICT.get(M.ComponentType, "")
-
- if ModuleType in [SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_DXE_CORE, SUP_MODULE_SMM_CORE, SUP_MODULE_MM_CORE_STANDALONE, SUP_MODULE_UEFI_APPLICATION]:
- return
-
- for Source in M.SourceFileList:
- if os.path.splitext(Source.Path)[1].lower() == ".dxs":
- Match = gDxsDependencyPattern.search(open(Source.Path).read())
- if Match:
- self.Depex = Match.group(1).strip()
- self.Source = "DXS"
- break
- else:
- self.Depex = M.DepexExpressionDict.get(M.ModuleType, "")
- self.ModuleDepex = " ".join(M.Module.DepexExpression[M.Arch, M.ModuleType])
- if not self.ModuleDepex:
- self.ModuleDepex = "(None)"
-
- LibDepexList = []
- for Lib in M.DependentLibraryList:
- LibDepex = " ".join(Lib.DepexExpression[M.Arch, M.ModuleType]).strip()
- if LibDepex != "":
- LibDepexList.append("(" + LibDepex + ")")
- self.LibraryDepex = " AND ".join(LibDepexList)
- if not self.LibraryDepex:
- self.LibraryDepex = "(None)"
- self.Source = "INF"
-
- ##
- # 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
- #
- def GenerateReport(self, File, GlobalDepexParser):
- if not self.Depex:
- return
- FileWrite(File, gSubSectionStart)
- if os.path.isfile(self._DepexFileName):
- try:
- DepexStatements = GlobalDepexParser.ParseDepexFile(self._DepexFileName)
- FileWrite(File, "Final Dependency Expression (DEPEX) Instructions")
- for DepexStatement in DepexStatements:
- FileWrite(File, " %s" % DepexStatement)
- FileWrite(File, gSubSectionSep)
- except:
- EdkLogger.warn(None, "Dependency expression file is corrupted", self._DepexFileName)
-
- FileWrite(File, "Dependency Expression (DEPEX) from %s" % self.Source)
-
- if self.Source == "INF":
- FileWrite(File, self.Depex, True)
- FileWrite(File, gSubSectionSep)
- FileWrite(File, "From Module INF: %s" % self.ModuleDepex, True)
- FileWrite(File, "From Library INF: %s" % self.LibraryDepex, True)
- else:
- FileWrite(File, self.Depex)
- FileWrite(File, gSubSectionEnd)
-
-##
-# Reports dependency expression information
-#
-# This class reports the module build flags subsection in the build report file.
-#
-class BuildFlagsReport(object):
- ##
- # 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
- #
- def __init__(self, M):
- BuildOptions = {}
- #
- # Add build flags according to source file extension so that
- # irrelevant ones can be filtered out.
- #
- for Source in M.SourceFileList:
- Ext = os.path.splitext(Source.File)[1].lower()
- if Ext in [".c", ".cc", ".cpp"]:
- BuildOptions["CC"] = 1
- elif Ext in [".s", ".asm"]:
- BuildOptions["PP"] = 1
- BuildOptions["ASM"] = 1
- elif Ext in [".vfr"]:
- BuildOptions["VFRPP"] = 1
- BuildOptions["VFR"] = 1
- elif Ext in [".dxs"]:
- BuildOptions["APP"] = 1
- BuildOptions["CC"] = 1
- elif Ext in [".asl"]:
- BuildOptions["ASLPP"] = 1
- BuildOptions["ASL"] = 1
- elif Ext in [".aslc"]:
- BuildOptions["ASLCC"] = 1
- BuildOptions["ASLDLINK"] = 1
- BuildOptions["CC"] = 1
- elif Ext in [".asm16"]:
- BuildOptions["ASMLINK"] = 1
- BuildOptions["SLINK"] = 1
- BuildOptions["DLINK"] = 1
-
- #
- # Save module build flags.
- #
- self.ToolChainTag = M.ToolChain
- self.BuildFlags = {}
- for Tool in BuildOptions:
- self.BuildFlags[Tool + "_FLAGS"] = M.BuildOption.get(Tool, {}).get("FLAGS", "")
-
- ##
- # 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
- #
- def GenerateReport(self, File):
- FileWrite(File, gSubSectionStart)
- FileWrite(File, "Build Flags")
- FileWrite(File, "Tool Chain Tag: %s" % self.ToolChainTag)
- for Tool in self.BuildFlags:
- FileWrite(File, gSubSectionSep)
- FileWrite(File, "%s = %s" % (Tool, self.BuildFlags[Tool]), True)
-
- FileWrite(File, gSubSectionEnd)
-
-
-##
-# 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.
-#
-class ModuleReport(object):
- ##
- # 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
- #
- def __init__(self, M, ReportType):
- self.ModuleName = M.Module.BaseName
- self.ModuleInfPath = M.MetaFile.File
- self.ModuleArch = M.Arch
- self.FileGuid = M.Guid
- self.Size = 0
- self.BuildTimeStamp = None
- self.Hash = 0
- self.DriverType = ""
- if not M.IsLibrary:
- ModuleType = M.ModuleType
- if not ModuleType:
- ModuleType = COMPONENT_TO_MODULE_MAP_DICT.get(M.ComponentType, "")
- #
- # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
- #
- if ModuleType == SUP_MODULE_DXE_SMM_DRIVER:
- PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000")
- if int(PiSpec, 0) >= 0x0001000A:
- ModuleType = "SMM_DRIVER"
- self.DriverType = gDriverTypeMap.get(ModuleType, "0x2 (FREE_FORM)")
- self.UefiSpecVersion = M.Module.Specification.get("UEFI_SPECIFICATION_VERSION", "")
- self.PiSpecVersion = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "")
- self.PciDeviceId = M.Module.Defines.get("PCI_DEVICE_ID", "")
- self.PciVendorId = M.Module.Defines.get("PCI_VENDOR_ID", "")
- self.PciClassCode = M.Module.Defines.get("PCI_CLASS_CODE", "")
- self.BuildTime = M.BuildTime
-
- self._BuildDir = M.BuildDir
- 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.
- #
- for Pcd in M.ModulePcdList + M.LibraryPcdList:
- self.ModulePcdSet.setdefault((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Type), (Pcd.InfDefaultValue, Pcd.DefaultValue))
-
- self.LibraryReport = None
- if "LIBRARY" in ReportType:
- self.LibraryReport = LibraryReport(M)
-
- self.DepexReport = None
- if "DEPEX" in ReportType:
- self.DepexReport = DepexReport(M)
-
- if "BUILD_FLAGS" in ReportType:
- self.BuildFlagsReport = BuildFlagsReport(M)
-
-
- ##
- # 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):
- FileWrite(File, gSectionStart)
-
- FwReportFileName = os.path.join(self._BuildDir, "OUTPUT", self.ModuleName + ".txt")
- if os.path.isfile(FwReportFileName):
- try:
- FileContents = open(FwReportFileName).read()
- Match = gModuleSizePattern.search(FileContents)
- if Match:
- self.Size = int(Match.group(1))
-
- Match = gTimeStampPattern.search(FileContents)
- if Match:
- self.BuildTimeStamp = datetime.utcfromtimestamp(int(Match.group(1)))
- except IOError:
- EdkLogger.warn(None, "Fail to read report file", FwReportFileName)
-
- if "HASH" in ReportType:
- OutputDir = os.path.join(self._BuildDir, "OUTPUT")
- DefaultEFIfile = os.path.join(OutputDir, self.ModuleName + ".efi")
- if os.path.isfile(DefaultEFIfile):
- Tempfile = os.path.join(OutputDir, self.ModuleName + "_hash.tmp")
- # rebase the efi image since its base address may not zero
- cmd = ["GenFw", "--rebase", str(0), "-o", Tempfile, DefaultEFIfile]
- try:
- PopenObject = subprocess.Popen(' '.join(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
- except Exception as X:
- EdkLogger.error("GenFw", COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0]))
- EndOfProcedure = threading.Event()
- EndOfProcedure.clear()
- if PopenObject.stderr:
- StdErrThread = threading.Thread(target=ReadMessage, args=(PopenObject.stderr, EdkLogger.quiet, EndOfProcedure))
- StdErrThread.setName("STDERR-Redirector")
- StdErrThread.setDaemon(False)
- StdErrThread.start()
- # waiting for program exit
- PopenObject.wait()
- if PopenObject.stderr:
- StdErrThread.join()
- if PopenObject.returncode != 0:
- EdkLogger.error("GenFw", COMMAND_FAILURE, "Failed to generate firmware hash image for %s" % (DefaultEFIfile))
- if os.path.isfile(Tempfile):
- self.Hash = hashlib.sha1()
- buf = open(Tempfile, 'rb').read()
- if self.Hash.update(buf):
- self.Hash = self.Hash.update(buf)
- self.Hash = self.Hash.hexdigest()
- os.remove(Tempfile)
-
- FileWrite(File, "Module Summary")
- FileWrite(File, "Module Name: %s" % self.ModuleName)
- FileWrite(File, "Module Arch: %s" % self.ModuleArch)
- FileWrite(File, "Module INF Path: %s" % self.ModuleInfPath)
- FileWrite(File, "File GUID: %s" % self.FileGuid)
- if self.Size:
- FileWrite(File, "Size: 0x%X (%.2fK)" % (self.Size, self.Size / 1024.0))
- if self.Hash:
- FileWrite(File, "SHA1 HASH: %s *%s" % (self.Hash, self.ModuleName + ".efi"))
- if self.BuildTimeStamp:
- FileWrite(File, "Build Time Stamp: %s" % self.BuildTimeStamp)
- if self.BuildTime:
- FileWrite(File, "Module Build Time: %s" % self.BuildTime)
- if self.DriverType:
- FileWrite(File, "Driver Type: %s" % self.DriverType)
- if self.UefiSpecVersion:
- FileWrite(File, "UEFI Spec Version: %s" % self.UefiSpecVersion)
- if self.PiSpecVersion:
- FileWrite(File, "PI Spec Version: %s" % self.PiSpecVersion)
- if self.PciDeviceId:
- FileWrite(File, "PCI Device ID: %s" % self.PciDeviceId)
- if self.PciVendorId:
- FileWrite(File, "PCI Vendor ID: %s" % self.PciVendorId)
- if self.PciClassCode:
- FileWrite(File, "PCI Class Code: %s" % self.PciClassCode)
-
- FileWrite(File, gSectionSep)
-
- if "PCD" in ReportType:
- GlobalPcdReport.GenerateReport(File, self.ModulePcdSet,self.FileGuid)
-
- if "LIBRARY" in ReportType:
- self.LibraryReport.GenerateReport(File)
-
- if "DEPEX" in ReportType:
- self.DepexReport.GenerateReport(File, GlobalDepexParser)
-
- if "BUILD_FLAGS" in ReportType:
- self.BuildFlagsReport.GenerateReport(File)
-
- if "FIXED_ADDRESS" in ReportType and self.FileGuid:
- GlobalPredictionReport.GenerateReport(File, self.FileGuid)
-
- FileWrite(File, gSectionEnd)
-
-def ReadMessage(From, To, ExitFlag):
- while True:
- # read one line a time
- Line = From.readline()
- # empty string means "end"
- if Line is not None and Line != b"":
- To(Line.rstrip().decode(encoding='utf-8', errors='ignore'))
- else:
- break
- if ExitFlag.isSet():
- break
-
-##
-# Reports platform and module PCD information
-#
-# This class reports the platform PCD section and module PCD subsection
-# in the build report file.
-#
-class PcdReport(object):
- ##
- # 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
- #
- def __init__(self, Wa):
- self.AllPcds = {}
- self.UnusedPcds = {}
- self.ConditionalPcds = {}
- self.MaxLen = 0
- self.Arch = None
- if Wa.FdfProfile:
- self.FdfPcdSet = Wa.FdfProfile.PcdDict
- else:
- self.FdfPcdSet = {}
-
- self.DefaultStoreSingle = True
- self.SkuSingle = True
- if GlobalData.gDefaultStores and len(GlobalData.gDefaultStores) > 1:
- self.DefaultStoreSingle = False
- if GlobalData.gSkuids and len(GlobalData.gSkuids) > 1:
- self.SkuSingle = False
-
- self.ModulePcdOverride = {}
- for Pa in Wa.AutoGenObjectList:
- self.Arch = Pa.Arch
- #
- # Collect all platform referenced PCDs and grouped them by PCD token space
- # GUID C Names
- #
- for Pcd in Pa.AllPcdList:
- PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
- if Pcd not in PcdList:
- PcdList.append(Pcd)
- if len(Pcd.TokenCName) > self.MaxLen:
- self.MaxLen = len(Pcd.TokenCName)
- #
- # Collect the PCD defined in DSC/FDF file, but not used in module
- #
- UnusedPcdFullList = []
- StructPcdDict = GlobalData.gStructurePcd.get(self.Arch, collections.OrderedDict())
- for Name, Guid in StructPcdDict:
- if (Name, Guid) not in Pa.Platform.Pcds:
- Pcd = StructPcdDict[(Name, Guid)]
- PcdList = self.AllPcds.setdefault(Guid, {}).setdefault(Pcd.Type, [])
- if Pcd not in PcdList and Pcd not in UnusedPcdFullList:
- UnusedPcdFullList.append(Pcd)
- for item in Pa.Platform.Pcds:
- Pcd = Pa.Platform.Pcds[item]
- if not Pcd.Type:
- # check the Pcd in FDF file, whether it is used in module first
- for T in PCD_TYPE_LIST:
- PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(T, [])
- if Pcd in PcdList:
- Pcd.Type = T
- break
- if not Pcd.Type:
- PcdTypeFlag = False
- for package in Pa.PackageList:
- for T in PCD_TYPE_LIST:
- if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T) in package.Pcds:
- Pcd.Type = T
- PcdTypeFlag = True
- if not Pcd.DatumType:
- Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T)].DatumType
- break
- if PcdTypeFlag:
- break
- if not Pcd.DatumType:
- PcdType = Pcd.Type
- # Try to remove Hii and Vpd suffix
- if PcdType.startswith(TAB_PCDS_DYNAMIC_EX):
- PcdType = TAB_PCDS_DYNAMIC_EX
- elif PcdType.startswith(TAB_PCDS_DYNAMIC):
- PcdType = TAB_PCDS_DYNAMIC
- for package in Pa.PackageList:
- if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType) in package.Pcds:
- Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType)].DatumType
- break
-
- PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
- UnusedPcdList = self.UnusedPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
- if Pcd in UnusedPcdList:
- UnusedPcdList.remove(Pcd)
- if Pcd not in PcdList and Pcd not in UnusedPcdFullList:
- UnusedPcdFullList.append(Pcd)
- if len(Pcd.TokenCName) > self.MaxLen:
- self.MaxLen = len(Pcd.TokenCName)
-
- if GlobalData.gConditionalPcds:
- for PcdItem in GlobalData.gConditionalPcds:
- if '.' in PcdItem:
- (TokenSpaceGuidCName, TokenCName) = PcdItem.split('.')
- if (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:
- Pcd = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)]
- PcdList = self.ConditionalPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
- if Pcd not in PcdList:
- PcdList.append(Pcd)
-
- UnusedPcdList = []
- if UnusedPcdFullList:
- for Pcd in UnusedPcdFullList:
- if Pcd.TokenSpaceGuidCName + '.' + Pcd.TokenCName in GlobalData.gConditionalPcds:
- continue
- UnusedPcdList.append(Pcd)
-
- for Pcd in UnusedPcdList:
- PcdList = self.UnusedPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
- if Pcd not in PcdList:
- PcdList.append(Pcd)
-
- for Module in Pa.Platform.Modules.values():
- #
- # Collect module override PCDs
- #
- for ModulePcd in Module.M.ModulePcdList + Module.M.LibraryPcdList:
- TokenCName = ModulePcd.TokenCName
- TokenSpaceGuid = ModulePcd.TokenSpaceGuidCName
- ModuleDefault = ModulePcd.DefaultValue
- ModulePath = os.path.basename(Module.M.MetaFile.File)
- self.ModulePcdOverride.setdefault((TokenCName, TokenSpaceGuid), {})[ModulePath] = ModuleDefault
-
-
- #
- # Collect PCD DEC default value.
- #
- self.DecPcdDefault = {}
- self._GuidDict = {}
- for Pa in Wa.AutoGenObjectList:
- for Package in Pa.PackageList:
- Guids = Package.Guids
- self._GuidDict.update(Guids)
- for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:
- DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue
- self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)
- #
- # Collect PCDs defined in DSC common section
- #
- self.DscPcdDefault = {}
- for Pa in Wa.AutoGenObjectList:
- for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:
- DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DscDefaultValue
- if DscDefaultValue:
- self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
-
- def GenerateReport(self, File, ModulePcdSet,ModuleGuid=None):
- if not ModulePcdSet:
- if self.ConditionalPcds:
- self.GenerateReportDetail(File, ModulePcdSet, 1)
- if self.UnusedPcds:
- IsEmpty = True
- for Token in self.UnusedPcds:
- TokenDict = self.UnusedPcds[Token]
- for Type in TokenDict:
- if TokenDict[Type]:
- IsEmpty = False
- break
- if not IsEmpty:
- break
- if not IsEmpty:
- self.GenerateReportDetail(File, ModulePcdSet, 2)
- self.GenerateReportDetail(File, ModulePcdSet,ModuleGuid = ModuleGuid)
-
- ##
- # 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 ReportySubType 0 means platform/module PCD report, 1 means Conditional
- # directives section report, 2 means Unused Pcds section report
- # @param DscOverridePcds Module DSC override PCDs set
- #
- def GenerateReportDetail(self, File, ModulePcdSet, ReportSubType = 0,ModuleGuid=None):
- PcdDict = self.AllPcds
- if ReportSubType == 1:
- PcdDict = self.ConditionalPcds
- elif ReportSubType == 2:
- PcdDict = self.UnusedPcds
-
- if not ModulePcdSet:
- FileWrite(File, gSectionStart)
- if ReportSubType == 1:
- FileWrite(File, "Conditional Directives used by the build system")
- elif ReportSubType == 2:
- FileWrite(File, "PCDs not used by modules or in conditional directives")
- else:
- FileWrite(File, "Platform Configuration Database Report")
-
- FileWrite(File, " *B - PCD override in the build option")
- FileWrite(File, " *P - Platform scoped PCD override in DSC file")
- FileWrite(File, " *F - Platform scoped PCD override in FDF file")
- if not ReportSubType:
- FileWrite(File, " *M - Module scoped PCD override")
- FileWrite(File, gSectionSep)
- else:
- if not ReportSubType and ModulePcdSet:
- #
- # For module PCD sub-section
- #
- FileWrite(File, gSubSectionStart)
- FileWrite(File, TAB_BRG_PCD)
- FileWrite(File, gSubSectionSep)
- AllPcdDict = {}
- for Key in PcdDict:
- AllPcdDict[Key] = {}
- for Type in PcdDict[Key]:
- for Pcd in PcdDict[Key][Type]:
- AllPcdDict[Key][(Pcd.TokenCName, Type)] = Pcd
- for Key in sorted(AllPcdDict):
- #
- # Group PCD by their token space GUID C Name
- #
- First = True
- for PcdTokenCName, Type in sorted(AllPcdDict[Key]):
- #
- # Group PCD by their usage type
- #
- Pcd = AllPcdDict[Key][(PcdTokenCName, Type)]
- TypeName, DecType = gPcdTypeMap.get(Type, ("", Type))
- MixedPcdFlag = False
- if GlobalData.MixedPcd:
- for PcdKey in GlobalData.MixedPcd:
- if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdKey]:
- PcdTokenCName = PcdKey[0]
- MixedPcdFlag = True
- if MixedPcdFlag and not ModulePcdSet:
- continue
- #
- # Get PCD default value and their override relationship
- #
- DecDefaultValue = self.DecPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, DecType))
- DscDefaultValue = self.DscPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))
- DscDefaultValBak = DscDefaultValue
- Field = ''
- for (CName, Guid, Field) in self.FdfPcdSet:
- if CName == PcdTokenCName and Guid == Key:
- DscDefaultValue = self.FdfPcdSet[(CName, Guid, Field)]
- break
- if DscDefaultValue != DscDefaultValBak:
- try:
- DscDefaultValue = ValueExpressionEx(DscDefaultValue, Pcd.DatumType, self._GuidDict)(True)
- except BadExpression as DscDefaultValue:
- EdkLogger.error('BuildReport', FORMAT_INVALID, "PCD Value: %s, Type: %s" %(DscDefaultValue, Pcd.DatumType))
-
- InfDefaultValue = None
-
- PcdValue = DecDefaultValue
- if DscDefaultValue:
- PcdValue = DscDefaultValue
- #The DefaultValue of StructurePcd already be the latest, no need to update.
- if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
- Pcd.DefaultValue = PcdValue
- PcdComponentValue = None
- if ModulePcdSet is not None:
- if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type) not in ModulePcdSet:
- continue
- InfDefaultValue, PcdComponentValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]
- PcdValue = PcdComponentValue
- #The DefaultValue of StructurePcd already be the latest, no need to update.
- if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
- Pcd.DefaultValue = PcdValue
- if InfDefaultValue:
- try:
- InfDefaultValue = ValueExpressionEx(InfDefaultValue, Pcd.DatumType, self._GuidDict)(True)
- except BadExpression as InfDefaultValue:
- EdkLogger.error('BuildReport', FORMAT_INVALID, "PCD Value: %s, Type: %s" % (InfDefaultValue, Pcd.DatumType))
- if InfDefaultValue == "":
- InfDefaultValue = None
-
- BuildOptionMatch = False
- if GlobalData.BuildOptionPcd:
- for pcd in GlobalData.BuildOptionPcd:
- if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) == (pcd[0], pcd[1]):
- if pcd[2]:
- continue
- PcdValue = pcd[3]
- #The DefaultValue of StructurePcd already be the latest, no need to update.
- if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
- Pcd.DefaultValue = PcdValue
- BuildOptionMatch = True
- break
-
- if First:
- if ModulePcdSet is None:
- FileWrite(File, "")
- FileWrite(File, Key)
- First = False
-
-
- if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:
- if PcdValue.startswith('0') and not PcdValue.lower().startswith('0x') and \
- len(PcdValue) > 1 and PcdValue.lstrip('0'):
- PcdValue = PcdValue.lstrip('0')
- PcdValueNumber = int(PcdValue.strip(), 0)
- if DecDefaultValue is None:
- DecMatch = True
- else:
- if DecDefaultValue.startswith('0') and not DecDefaultValue.lower().startswith('0x') and \
- len(DecDefaultValue) > 1 and DecDefaultValue.lstrip('0'):
- DecDefaultValue = DecDefaultValue.lstrip('0')
- DecDefaultValueNumber = int(DecDefaultValue.strip(), 0)
- DecMatch = (DecDefaultValueNumber == PcdValueNumber)
-
- if InfDefaultValue is None:
- InfMatch = True
- else:
- if InfDefaultValue.startswith('0') and not InfDefaultValue.lower().startswith('0x') and \
- len(InfDefaultValue) > 1 and InfDefaultValue.lstrip('0'):
- InfDefaultValue = InfDefaultValue.lstrip('0')
- InfDefaultValueNumber = int(InfDefaultValue.strip(), 0)
- InfMatch = (InfDefaultValueNumber == PcdValueNumber)
-
- if DscDefaultValue is None:
- DscMatch = True
- else:
- if DscDefaultValue.startswith('0') and not DscDefaultValue.lower().startswith('0x') and \
- len(DscDefaultValue) > 1 and DscDefaultValue.lstrip('0'):
- DscDefaultValue = DscDefaultValue.lstrip('0')
- DscDefaultValueNumber = int(DscDefaultValue.strip(), 0)
- DscMatch = (DscDefaultValueNumber == PcdValueNumber)
- else:
- if DecDefaultValue is None:
- DecMatch = True
- else:
- DecMatch = (DecDefaultValue.strip() == PcdValue.strip())
-
- if InfDefaultValue is None:
- InfMatch = True
- else:
- InfMatch = (InfDefaultValue.strip() == PcdValue.strip())
-
- if DscDefaultValue is None:
- DscMatch = True
- else:
- DscMatch = (DscDefaultValue.strip() == PcdValue.strip())
-
- IsStructure = False
- if self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
- IsStructure = True
- if TypeName in ('DYNVPD', 'DEXVPD'):
- SkuInfoList = Pcd.SkuInfoList
- Pcd = GlobalData.gStructurePcd[self.Arch][(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)]
- if ModulePcdSet and ModulePcdSet.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type)):
- InfDefaultValue, PcdComponentValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]
- DscDefaultValBak = Pcd.DefaultValue
- Pcd.DefaultValue = PcdComponentValue
-
- Pcd.DatumType = Pcd.StructName
- if TypeName in ('DYNVPD', 'DEXVPD'):
- Pcd.SkuInfoList = SkuInfoList
- if Pcd.PcdValueFromComm or Pcd.PcdFieldValueFromComm:
- BuildOptionMatch = True
- DecMatch = False
- elif Pcd.PcdValueFromFdf or Pcd.PcdFieldValueFromFdf:
- DscDefaultValue = True
- DscMatch = True
- DecMatch = False
- else:
- if Pcd.Type in PCD_DYNAMIC_TYPE_SET | PCD_DYNAMIC_EX_TYPE_SET:
- DscOverride = False
- if Pcd.DefaultFromDSC:
- DscOverride = True
- else:
- DictLen = 0
- for item in Pcd.SkuOverrideValues:
- DictLen += len(Pcd.SkuOverrideValues[item])
- if not DictLen:
- DscOverride = False
- else:
- if not Pcd.SkuInfoList:
- OverrideValues = Pcd.SkuOverrideValues
- if OverrideValues:
- for Data in OverrideValues.values():
- Struct = list(Data.values())
- if Struct:
- DscOverride = self.ParseStruct(Struct[0])
- break
- else:
- SkuList = sorted(Pcd.SkuInfoList.keys())
- for Sku in SkuList:
- SkuInfo = Pcd.SkuInfoList[Sku]
- if SkuInfo.DefaultStoreDict:
- DefaultStoreList = sorted(SkuInfo.DefaultStoreDict.keys())
- for DefaultStore in DefaultStoreList:
- OverrideValues = Pcd.SkuOverrideValues.get(Sku)
- if OverrideValues:
- DscOverride = self.ParseStruct(OverrideValues[DefaultStore])
- if DscOverride:
- break
- if DscOverride:
- break
- if DscOverride:
- DscDefaultValue = True
- DscMatch = True
- DecMatch = False
- else:
- DecMatch = True
- else:
- if Pcd.DscRawValue or (ModuleGuid and ModuleGuid.replace("-","S") in Pcd.PcdValueFromComponents):
- DscDefaultValue = True
- DscMatch = True
- DecMatch = False
- else:
- DscDefaultValue = False
- DecMatch = True
-
- #
- # Report PCD item according to their override relationship
- #
- if Pcd.DatumType == 'BOOLEAN':
- if DscDefaultValue:
- DscDefaultValue = str(int(DscDefaultValue, 0))
- if DecDefaultValue:
- DecDefaultValue = str(int(DecDefaultValue, 0))
- if InfDefaultValue:
- InfDefaultValue = str(int(InfDefaultValue, 0))
- if Pcd.DefaultValue:
- Pcd.DefaultValue = str(int(Pcd.DefaultValue, 0))
- if DecMatch:
- self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, ' ')
- elif InfDefaultValue and InfMatch:
- self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*M')
- elif BuildOptionMatch:
- self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*B')
- else:
- if PcdComponentValue:
- self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, PcdComponentValue, DecMatch, DecDefaultValue, '*M', ModuleGuid)
- elif DscDefaultValue and DscMatch:
- if (Pcd.TokenCName, Key, Field) in self.FdfPcdSet:
- self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*F')
- else:
- self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*P')
-
-
- if ModulePcdSet is None:
- if IsStructure:
- continue
- if not TypeName in ('PATCH', 'FLAG', 'FIXED'):
- continue
- if not BuildOptionMatch:
- ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {})
- for ModulePath in ModuleOverride:
- ModuleDefault = ModuleOverride[ModulePath]
- if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:
- if ModuleDefault.startswith('0') and not ModuleDefault.lower().startswith('0x') and \
- len(ModuleDefault) > 1 and ModuleDefault.lstrip('0'):
- ModuleDefault = ModuleDefault.lstrip('0')
- ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)
- Match = (ModulePcdDefaultValueNumber == PcdValueNumber)
- if Pcd.DatumType == 'BOOLEAN':
- ModuleDefault = str(ModulePcdDefaultValueNumber)
- else:
- Match = (ModuleDefault.strip() == PcdValue.strip())
- if Match:
- continue
- IsByteArray, ArrayList = ByteArrayForamt(ModuleDefault.strip())
- if IsByteArray:
- FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 15, ModulePath, '{'))
- for Array in ArrayList:
- FileWrite(File, Array)
- else:
- Value = ModuleDefault.strip()
- if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
- if Value.startswith(('0x', '0X')):
- Value = '{} ({:d})'.format(Value, int(Value, 0))
- else:
- Value = "0x{:X} ({})".format(int(Value, 0), Value)
- FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 15, ModulePath, Value))
-
- if ModulePcdSet is None:
- FileWrite(File, gSectionEnd)
- else:
- if not ReportSubType and ModulePcdSet:
- FileWrite(File, gSubSectionEnd)
-
- def ParseStruct(self, struct):
- HasDscOverride = False
- if struct:
- for _, Values in list(struct.items()):
- for Key, value in Values.items():
- if value[1] and value[1].endswith('.dsc'):
- HasDscOverride = True
- break
- if HasDscOverride == True:
- break
- return HasDscOverride
-
- def PrintPcdDefault(self, File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue):
- if not DscMatch and DscDefaultValue is not None:
- Value = DscDefaultValue.strip()
- IsByteArray, ArrayList = ByteArrayForamt(Value)
- if IsByteArray:
- FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', "{"))
- for Array in ArrayList:
- FileWrite(File, Array)
- else:
- if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
- if Value.startswith(('0x', '0X')):
- Value = '{} ({:d})'.format(Value, int(Value, 0))
- else:
- Value = "0x{:X} ({})".format(int(Value, 0), Value)
- FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', Value))
- if not InfMatch and InfDefaultValue is not None:
- Value = InfDefaultValue.strip()
- IsByteArray, ArrayList = ByteArrayForamt(Value)
- if IsByteArray:
- FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', "{"))
- for Array in ArrayList:
- FileWrite(File, Array)
- else:
- if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
- if Value.startswith(('0x', '0X')):
- Value = '{} ({:d})'.format(Value, int(Value, 0))
- else:
- Value = "0x{:X} ({})".format(int(Value, 0), Value)
- FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', Value))
-
- if not DecMatch and DecDefaultValue is not None:
- Value = DecDefaultValue.strip()
- IsByteArray, ArrayList = ByteArrayForamt(Value)
- if IsByteArray:
- FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', "{"))
- for Array in ArrayList:
- FileWrite(File, Array)
- else:
- if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
- if Value.startswith(('0x', '0X')):
- Value = '{} ({:d})'.format(Value, int(Value, 0))
- else:
- Value = "0x{:X} ({})".format(int(Value, 0), Value)
- FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', Value))
- if IsStructure:
- for filedvalues in Pcd.DefaultValues.values():
- self.PrintStructureInfo(File, filedvalues)
- if DecMatch and IsStructure:
- for filedvalues in Pcd.DefaultValues.values():
- self.PrintStructureInfo(File, filedvalues)
-
- def PrintPcdValue(self, File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, Flag = ' ',ModuleGuid=None):
- if not Pcd.SkuInfoList:
- Value = Pcd.DefaultValue
- IsByteArray, ArrayList = ByteArrayForamt(Value)
- if IsByteArray:
- FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '{'))
- for Array in ArrayList:
- FileWrite(File, Array)
- else:
- if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
- if Value.startswith('0') and not Value.lower().startswith('0x') and len(Value) > 1 and Value.lstrip('0'):
- Value = Value.lstrip('0')
- if Value.startswith(('0x', '0X')):
- Value = '{} ({:d})'.format(Value, int(Value, 0))
- else:
- Value = "0x{:X} ({})".format(int(Value, 0), Value)
- FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))
- if IsStructure:
- FiledOverrideFlag = False
- if (Pcd.TokenCName,Pcd.TokenSpaceGuidCName) in GlobalData.gPcdSkuOverrides:
- OverrideValues = GlobalData.gPcdSkuOverrides[(Pcd.TokenCName,Pcd.TokenSpaceGuidCName)]
- else:
- OverrideValues = Pcd.SkuOverrideValues
- FieldOverrideValues = None
- if OverrideValues:
- for Data in OverrideValues.values():
- Struct = list(Data.values())
- if Struct:
- FieldOverrideValues = Struct[0]
- FiledOverrideFlag = True
- break
- if Pcd.PcdFiledValueFromDscComponent and ModuleGuid and ModuleGuid.replace("-","S") in Pcd.PcdFiledValueFromDscComponent:
- FieldOverrideValues = Pcd.PcdFiledValueFromDscComponent[ModuleGuid.replace("-","S")]
- if FieldOverrideValues:
- OverrideFieldStruct = self.OverrideFieldValue(Pcd, FieldOverrideValues)
- self.PrintStructureInfo(File, OverrideFieldStruct)
-
- if not FiledOverrideFlag and (Pcd.PcdFieldValueFromComm or Pcd.PcdFieldValueFromFdf):
- OverrideFieldStruct = self.OverrideFieldValue(Pcd, {})
- self.PrintStructureInfo(File, OverrideFieldStruct)
- self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)
- else:
- FirstPrint = True
- SkuList = sorted(Pcd.SkuInfoList.keys())
- for Sku in SkuList:
- SkuInfo = Pcd.SkuInfoList[Sku]
- SkuIdName = SkuInfo.SkuIdName
- if TypeName in ('DYNHII', 'DEXHII'):
- if SkuInfo.DefaultStoreDict:
- DefaultStoreList = sorted(SkuInfo.DefaultStoreDict.keys())
- for DefaultStore in DefaultStoreList:
- Value = SkuInfo.DefaultStoreDict[DefaultStore]
- IsByteArray, ArrayList = ByteArrayForamt(Value)
- if Pcd.DatumType == 'BOOLEAN':
- Value = str(int(Value, 0))
- if FirstPrint:
- FirstPrint = False
- if IsByteArray:
- if self.DefaultStoreSingle and self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '{'))
- elif self.DefaultStoreSingle and not self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '{'))
- elif not self.DefaultStoreSingle and self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', '{'))
- else:
- FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', '{'))
- for Array in ArrayList:
- FileWrite(File, Array)
- else:
- if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
- if Value.startswith(('0x', '0X')):
- Value = '{} ({:d})'.format(Value, int(Value, 0))
- else:
- Value = "0x{:X} ({})".format(int(Value, 0), Value)
- if self.DefaultStoreSingle and self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))
- elif self.DefaultStoreSingle and not self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
- elif not self.DefaultStoreSingle and self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', Value))
- else:
- FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', Value))
- else:
- if IsByteArray:
- if self.DefaultStoreSingle and self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '{'))
- elif self.DefaultStoreSingle and not self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '{'))
- elif not self.DefaultStoreSingle and self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', '{'))
- else:
- FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', '{'))
- for Array in ArrayList:
- FileWrite(File, Array)
- else:
- if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
- if Value.startswith(('0x', '0X')):
- Value = '{} ({:d})'.format(Value, int(Value, 0))
- else:
- Value = "0x{:X} ({})".format(int(Value, 0), Value)
- if self.DefaultStoreSingle and self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', Value))
- elif self.DefaultStoreSingle and not self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
- elif not self.DefaultStoreSingle and self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', Value))
- else:
- FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', Value))
- FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset))
- if IsStructure:
- OverrideValues = Pcd.SkuOverrideValues.get(Sku)
- if OverrideValues:
- OverrideFieldStruct = self.OverrideFieldValue(Pcd, OverrideValues[DefaultStore])
- self.PrintStructureInfo(File, OverrideFieldStruct)
- self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)
- else:
- Value = SkuInfo.DefaultValue
- IsByteArray, ArrayList = ByteArrayForamt(Value)
- if Pcd.DatumType == 'BOOLEAN':
- Value = str(int(Value, 0))
- if FirstPrint:
- FirstPrint = False
- if IsByteArray:
- if self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', "{"))
- else:
- FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', "{"))
- for Array in ArrayList:
- FileWrite(File, Array)
- else:
- if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
- if Value.startswith(('0x', '0X')):
- Value = '{} ({:d})'.format(Value, int(Value, 0))
- else:
- Value = "0x{:X} ({})".format(int(Value, 0), Value)
- if self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))
- else:
- FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
- else:
- if IsByteArray:
- if self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', "{"))
- else:
- FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', "{"))
- for Array in ArrayList:
- FileWrite(File, Array)
- else:
- if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
- if Value.startswith(('0x', '0X')):
- Value = '{} ({:d})'.format(Value, int(Value, 0))
- else:
- Value = "0x{:X} ({})".format(int(Value, 0), Value)
- if self.SkuSingle:
- FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', Value))
- else:
- FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
- if TypeName in ('DYNVPD', 'DEXVPD'):
- FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset))
- VPDPcdItem = (Pcd.TokenSpaceGuidCName + '.' + PcdTokenCName, SkuIdName, SkuInfo.VpdOffset, Pcd.MaxDatumSize, SkuInfo.DefaultValue)
- if VPDPcdItem not in VPDPcdList:
- PcdGuidList = self.UnusedPcds.get(Pcd.TokenSpaceGuidCName)
- if PcdGuidList:
- PcdList = PcdGuidList.get(Pcd.Type)
- if not PcdList:
- VPDPcdList.append(VPDPcdItem)
- for VpdPcd in PcdList:
- if PcdTokenCName == VpdPcd.TokenCName:
- break
- else:
- VPDPcdList.append(VPDPcdItem)
- if IsStructure:
- FiledOverrideFlag = False
- OverrideValues = Pcd.SkuOverrideValues.get(Sku)
- if OverrideValues:
- Keys = list(OverrideValues.keys())
- OverrideFieldStruct = self.OverrideFieldValue(Pcd, OverrideValues[Keys[0]])
- self.PrintStructureInfo(File, OverrideFieldStruct)
- FiledOverrideFlag = True
- if not FiledOverrideFlag and (Pcd.PcdFieldValueFromComm or Pcd.PcdFieldValueFromFdf):
- OverrideFieldStruct = self.OverrideFieldValue(Pcd, {})
- self.PrintStructureInfo(File, OverrideFieldStruct)
- self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)
-
- def OverrideFieldValue(self, Pcd, OverrideStruct):
- OverrideFieldStruct = collections.OrderedDict()
- if OverrideStruct:
- for _, Values in OverrideStruct.items():
- for Key,value in Values.items():
- if value[1] and value[1].endswith('.dsc'):
- OverrideFieldStruct[Key] = value
- if Pcd.PcdFieldValueFromFdf:
- for Key, Values in Pcd.PcdFieldValueFromFdf.items():
- if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:
- continue
- OverrideFieldStruct[Key] = Values
- if Pcd.PcdFieldValueFromComm:
- for Key, Values in Pcd.PcdFieldValueFromComm.items():
- if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:
- continue
- OverrideFieldStruct[Key] = Values
- return OverrideFieldStruct
-
- def PrintStructureInfo(self, File, Struct):
- for Key, Value in sorted(Struct.items(), key=lambda x: x[0]):
- if Value[1] and 'build command options' in Value[1]:
- FileWrite(File, ' *B %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
- elif Value[1] and Value[1].endswith('.fdf'):
- FileWrite(File, ' *F %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
- else:
- FileWrite(File, ' %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
-
- def StrtoHex(self, value):
- try:
- value = hex(int(value))
- return value
- except:
- if value.startswith("L\"") and value.endswith("\""):
- valuelist = []
- for ch in value[2:-1]:
- valuelist.append(hex(ord(ch)))
- valuelist.append('0x00')
- return valuelist
- elif value.startswith("\"") and value.endswith("\""):
- return hex(ord(value[1:-1]))
- elif value.startswith("{") and value.endswith("}"):
- valuelist = []
- if ',' not in value:
- return value[1:-1]
- for ch in value[1:-1].split(','):
- ch = ch.strip()
- if ch.startswith('0x') or ch.startswith('0X'):
- valuelist.append(ch)
- continue
- try:
- valuelist.append(hex(int(ch.strip())))
- except:
- pass
- return valuelist
- else:
- return value
-
- def IsStructurePcd(self, PcdToken, PcdTokenSpaceGuid):
- if GlobalData.gStructurePcd and (self.Arch in GlobalData.gStructurePcd) and ((PcdToken, PcdTokenSpaceGuid) in GlobalData.gStructurePcd[self.Arch]):
- return True
- else:
- return False
-
-##
-# 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.
-#
-class PredictionReport(object):
- ##
- # Constructor function for class PredictionReport
- #
- # This constructor function generates PredictionReport object for the platform.
- #
- # @param self: The object pointer
- # @param Wa Workspace context information
- #
- def __init__(self, Wa):
- self._MapFileName = os.path.join(Wa.BuildDir, Wa.Name + ".map")
- self._MapFileParsed = False
- self._EotToolInvoked = False
- self._FvDir = Wa.FvDir
- self._EotDir = Wa.BuildDir
- self._FfsEntryPoint = {}
- self._GuidMap = {}
- self._SourceList = []
- self.FixedMapDict = {}
- self.ItemList = []
- self.MaxLen = 0
-
- #
- # Collect all platform reference source files and GUID C Name
- #
- for Pa in Wa.AutoGenObjectList:
- for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList:
- #
- # BASE typed modules are EFI agnostic, so we need not scan
- # their source code to find PPI/Protocol produce or consume
- # information.
- #
- if Module.ModuleType == SUP_MODULE_BASE:
- continue
- #
- # Add module referenced source files
- #
- self._SourceList.append(str(Module))
- IncludeList = {}
- for Source in Module.SourceFileList:
- if os.path.splitext(str(Source))[1].lower() == ".c":
- self._SourceList.append(" " + str(Source))
- FindIncludeFiles(Source.Path, Module.IncludePathList, IncludeList)
- for IncludeFile in IncludeList.values():
- self._SourceList.append(" " + IncludeFile)
-
- for Guid in Module.PpiList:
- self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.PpiList[Guid])
- for Guid in Module.ProtocolList:
- self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.ProtocolList[Guid])
- for Guid in Module.GuidList:
- self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.GuidList[Guid])
-
- if Module.Guid and not Module.IsLibrary:
- EntryPoint = " ".join(Module.Module.ModuleEntryPointList)
-
- RealEntryPoint = "_ModuleEntryPoint"
-
- self._FfsEntryPoint[Module.Guid.upper()] = (EntryPoint, RealEntryPoint)
-
-
- #
- # Collect platform firmware volume list as the input of EOT.
- #
- self._FvList = []
- if Wa.FdfProfile:
- for Fd in Wa.FdfProfile.FdDict:
- for FdRegion in Wa.FdfProfile.FdDict[Fd].RegionList:
- if FdRegion.RegionType != BINARY_FILE_TYPE_FV:
- continue
- for FvName in FdRegion.RegionDataList:
- if FvName in self._FvList:
- continue
- self._FvList.append(FvName)
- for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
- for Section in Ffs.SectionList:
- try:
- for FvSection in Section.SectionList:
- if FvSection.FvName in self._FvList:
- continue
- self._FvList.append(FvSection.FvName)
- 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
- #
- def _ParseMapFile(self):
- if self._MapFileParsed:
- return
- self._MapFileParsed = True
- if os.path.isfile(self._MapFileName):
- try:
- FileContents = open(self._MapFileName).read()
- for Match in gMapFileItemPattern.finditer(FileContents):
- AddressType = Match.group(1)
- BaseAddress = Match.group(2)
- EntryPoint = Match.group(3)
- Guid = Match.group(4).upper()
- List = self.FixedMapDict.setdefault(Guid, [])
- List.append((AddressType, BaseAddress, "*I"))
- List.append((AddressType, EntryPoint, "*E"))
- except:
- EdkLogger.warn(None, "Cannot open file to read", self._MapFileName)
-
- ##
- # 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
- #
- def _InvokeEotTool(self):
- if self._EotToolInvoked:
- return
-
- self._EotToolInvoked = True
- FvFileList = []
- for FvName in self._FvList:
- FvFile = os.path.join(self._FvDir, FvName + ".Fv")
- if os.path.isfile(FvFile):
- FvFileList.append(FvFile)
-
- if len(FvFileList) == 0:
- 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.
- #
- SourceList = os.path.join(self._EotDir, "SourceFile.txt")
- GuidList = os.path.join(self._EotDir, "GuidList.txt")
- DispatchList = os.path.join(self._EotDir, "Dispatch.txt")
-
- TempFile = []
- for Item in self._SourceList:
- FileWrite(TempFile, Item)
- SaveFileOnChange(SourceList, "".join(TempFile), False)
- TempFile = []
- for Key in self._GuidMap:
- FileWrite(TempFile, "%s %s" % (Key, self._GuidMap[Key]))
- SaveFileOnChange(GuidList, "".join(TempFile), False)
-
- try:
- from Eot.EotMain import Eot
-
- #
- # Invoke EOT tool and echo its runtime performance
- #
- EotStartTime = time.time()
- Eot(CommandLineOption=False, SourceFileList=SourceList, GuidList=GuidList,
- FvFileList=' '.join(FvFileList), Dispatch=DispatchList, IsInit=True)
- EotEndTime = time.time()
- EotDuration = time.strftime("%H:%M:%S", time.gmtime(int(round(EotEndTime - EotStartTime))))
- EdkLogger.quiet("EOT run time: %s\n" % EotDuration)
-
- #
- # Parse the output of EOT tool
- #
- for Line in open(DispatchList):
- if len(Line.split()) < 4:
- continue
- (Guid, Phase, FfsName, FilePath) = Line.split()
- Symbol = self._FfsEntryPoint.get(Guid, [FfsName, ""])[0]
- if len(Symbol) > self.MaxLen:
- self.MaxLen = len(Symbol)
- self.ItemList.append((Phase, Symbol, FilePath))
- 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
- #
- def _GenerateExecutionOrderReport(self, File):
- self._InvokeEotTool()
- if len(self.ItemList) == 0:
- return
- FileWrite(File, gSectionStart)
- FileWrite(File, "Execution Order Prediction")
- FileWrite(File, "*P PEI phase")
- FileWrite(File, "*D DXE phase")
- FileWrite(File, "*E Module INF entry point name")
- FileWrite(File, "*N Module notification function name")
-
- FileWrite(File, "Type %-*s %s" % (self.MaxLen, "Symbol", "Module INF Path"))
- FileWrite(File, gSectionSep)
- for Item in self.ItemList:
- FileWrite(File, "*%sE %-*s %s" % (Item[0], self.MaxLen, Item[1], Item[2]))
-
- FileWrite(File, gSectionStart)
-
- ##
- # 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
- #
- def _GenerateFixedAddressReport(self, File, Guid, NotifyList):
- self._ParseMapFile()
- FixedAddressList = self.FixedMapDict.get(Guid)
- if not FixedAddressList:
- return
-
- FileWrite(File, gSubSectionStart)
- FileWrite(File, "Fixed Address Prediction")
- FileWrite(File, "*I Image Loading Address")
- FileWrite(File, "*E Entry Point Address")
- FileWrite(File, "*N Notification Function Address")
- FileWrite(File, "*F Flash Address")
- FileWrite(File, "*M Memory Address")
- FileWrite(File, "*S SMM RAM Offset")
- FileWrite(File, "TOM Top of Memory")
-
- FileWrite(File, "Type Address Name")
- FileWrite(File, gSubSectionSep)
- for Item in FixedAddressList:
- Type = Item[0]
- Value = Item[1]
- Symbol = Item[2]
- if Symbol == "*I":
- Name = "(Image Base)"
- elif Symbol == "*E":
- Name = self._FfsEntryPoint.get(Guid, ["", "_ModuleEntryPoint"])[1]
- elif Symbol in NotifyList:
- Name = Symbol
- Symbol = "*N"
- else:
- continue
-
- if "Flash" in Type:
- Symbol += "F"
- elif "Memory" in Type:
- Symbol += "M"
- else:
- Symbol += "S"
-
- if Value[0] == "-":
- Value = "TOM" + Value
-
- FileWrite(File, "%s %-16s %s" % (Symbol, Value, Name))
-
- ##
- # 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.
- #
- def GenerateReport(self, File, Guid):
- if Guid:
- self._GenerateFixedAddressReport(File, Guid.upper(), [])
- else:
- self._GenerateExecutionOrderReport(File)
-
-##
-# 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
-#
-class FdRegionReport(object):
- ##
- # 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
- #
- def _DiscoverNestedFvList(self, FvName, Wa):
- FvDictKey=FvName.upper()
- if FvDictKey in Wa.FdfProfile.FvDict:
- for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
- for Section in Ffs.SectionList:
- try:
- for FvSection in Section.SectionList:
- if FvSection.FvName in self.FvList:
- continue
- self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName
- self.FvList.append(FvSection.FvName)
- self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0)
- self._DiscoverNestedFvList(FvSection.FvName, Wa)
- 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
- #
- def __init__(self, FdRegion, Wa):
- self.Type = FdRegion.RegionType
- self.BaseAddress = FdRegion.Offset
- self.Size = FdRegion.Size
- self.FvList = []
- self.FvInfo = {}
- self._GuidsDb = {}
- self._FvDir = Wa.FvDir
- self._WorkspaceDir = Wa.WorkspaceDir
-
- #
- # If the input FdRegion is not a firmware volume,
- # we are done.
- #
- if self.Type != BINARY_FILE_TYPE_FV:
- return
-
- #
- # Find all nested FVs in the FdRegion
- #
- for FvName in FdRegion.RegionDataList:
- if FvName in self.FvList:
- continue
- self.FvList.append(FvName)
- self.FvInfo[FvName] = ("Fd Region", self.BaseAddress, self.Size)
- self._DiscoverNestedFvList(FvName, Wa)
-
- PlatformPcds = {}
- #
- # Collect PCDs declared in DEC files.
- #
- for Pa in Wa.AutoGenObjectList:
- for Package in Pa.PackageList:
- for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:
- DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue
- PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue
- #
- # Collect PCDs defined in DSC file
- #
- for Pa in Wa.AutoGenObjectList:
- for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:
- DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue
- PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
-
- #
- # Add PEI and DXE a priori files GUIDs defined in PI specification.
- #
- self._GuidsDb[PEI_APRIORI_GUID] = "PEI Apriori"
- self._GuidsDb[DXE_APRIORI_GUID] = "DXE Apriori"
- #
- # Add ACPI table storage file
- #
- self._GuidsDb["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
-
- for Pa in Wa.AutoGenObjectList:
- for ModuleKey in Pa.Platform.Modules:
- M = Pa.Platform.Modules[ModuleKey].M
- InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File)
- self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath)
-
- #
- # Collect the GUID map in the FV firmware volume
- #
- for FvName in self.FvList:
- FvDictKey=FvName.upper()
- if FvDictKey in Wa.FdfProfile.FvDict:
- for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
- try:
- #
- # collect GUID map for binary EFI file in FDF file.
- #
- Guid = Ffs.NameGuid.upper()
- Match = gPcdGuidPattern.match(Ffs.NameGuid)
- if Match:
- PcdTokenspace = Match.group(1)
- PcdToken = Match.group(2)
- if (PcdToken, PcdTokenspace) in PlatformPcds:
- GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)]
- Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()
- for Section in Ffs.SectionList:
- try:
- ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName)
- self._GuidsDb[Guid] = ModuleSectFile
- 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
- #
- def _GenerateReport(self, File, Title, Type, BaseAddress, Size=0, FvName=None):
- FileWrite(File, gSubSectionStart)
- FileWrite(File, Title)
- FileWrite(File, "Type: %s" % Type)
- FileWrite(File, "Base Address: 0x%X" % BaseAddress)
-
- if self.Type == BINARY_FILE_TYPE_FV:
- FvTotalSize = 0
- FvTakenSize = 0
- FvFreeSize = 0
- if FvName.upper().endswith('.FV'):
- FileExt = FvName + ".txt"
- else:
- FileExt = FvName + ".Fv.txt"
-
- if not os.path.isfile(FileExt):
- FvReportFileName = mws.join(self._WorkspaceDir, FileExt)
- if not os.path.isfile(FvReportFileName):
- FvReportFileName = os.path.join(self._FvDir, FileExt)
- try:
- #
- # Collect size info in the firmware volume.
- #
- FvReport = open(FvReportFileName).read()
- Match = gFvTotalSizePattern.search(FvReport)
- if Match:
- FvTotalSize = int(Match.group(1), 16)
- Match = gFvTakenSizePattern.search(FvReport)
- if Match:
- FvTakenSize = int(Match.group(1), 16)
- FvFreeSize = FvTotalSize - FvTakenSize
- #
- # Write size information to the report file.
- #
- FileWrite(File, "Size: 0x%X (%.0fK)" % (FvTotalSize, FvTotalSize / 1024.0))
- FileWrite(File, "Fv Name: %s (%.1f%% Full)" % (FvName, FvTakenSize * 100.0 / FvTotalSize))
- FileWrite(File, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize, FvTakenSize / 1024.0))
- FileWrite(File, "Free Size: 0x%X (%.0fK)" % (FvFreeSize, FvFreeSize / 1024.0))
- FileWrite(File, "Offset Module")
- FileWrite(File, gSubSectionSep)
- #
- # Write module offset and module identification to the report file.
- #
- OffsetInfo = {}
- for Match in gOffsetGuidPattern.finditer(FvReport):
- Guid = Match.group(2).upper()
- OffsetInfo[Match.group(1)] = self._GuidsDb.get(Guid, Guid)
- OffsetList = sorted(OffsetInfo.keys())
- for Offset in OffsetList:
- FileWrite (File, "%s %s" % (Offset, OffsetInfo[Offset]))
- except IOError:
- EdkLogger.warn(None, "Fail to read report file", FvReportFileName)
- else:
- FileWrite(File, "Size: 0x%X (%.0fK)" % (Size, Size / 1024.0))
- FileWrite(File, gSubSectionEnd)
-
- ##
- # 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
- #
- def GenerateReport(self, File):
- if (len(self.FvList) > 0):
- for FvItem in self.FvList:
- Info = self.FvInfo[FvItem]
- self._GenerateReport(File, Info[0], TAB_FV_DIRECTORY, Info[1], Info[2], FvItem)
- else:
- self._GenerateReport(File, "FD Region", self.Type, self.BaseAddress, self.Size)
-
-##
-# Reports FD information
-#
-# This class reports the FD section in the build report file.
-# It collects flash device information for a platform.
-#
-class FdReport(object):
- ##
- # 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
- #
- def __init__(self, Fd, Wa):
- self.FdName = Fd.FdUiName
- self.BaseAddress = Fd.BaseAddress
- self.Size = Fd.Size
- self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList]
- self.FvPath = os.path.join(Wa.BuildDir, TAB_FV_DIRECTORY)
- self.VPDBaseAddress = 0
- self.VPDSize = 0
- for index, FdRegion in enumerate(Fd.RegionList):
- if str(FdRegion.RegionType) == 'FILE' and Wa.Platform.VpdToolGuid in str(FdRegion.RegionDataList):
- self.VPDBaseAddress = self.FdRegionList[index].BaseAddress
- self.VPDSize = self.FdRegionList[index].Size
- break
-
- ##
- # 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
- #
- def GenerateReport(self, File):
- FileWrite(File, gSectionStart)
- FileWrite(File, "Firmware Device (FD)")
- FileWrite(File, "FD Name: %s" % self.FdName)
- FileWrite(File, "Base Address: %s" % self.BaseAddress)
- FileWrite(File, "Size: 0x%X (%.0fK)" % (self.Size, self.Size / 1024.0))
- if len(self.FdRegionList) > 0:
- FileWrite(File, gSectionSep)
- for FdRegionItem in self.FdRegionList:
- FdRegionItem.GenerateReport(File)
-
- if VPDPcdList:
- VPDPcdList.sort(key=lambda x: int(x[2], 0))
- FileWrite(File, gSubSectionStart)
- FileWrite(File, "FD VPD Region")
- FileWrite(File, "Base Address: 0x%X" % self.VPDBaseAddress)
- FileWrite(File, "Size: 0x%X (%.0fK)" % (self.VPDSize, self.VPDSize / 1024.0))
- FileWrite(File, gSubSectionSep)
- for item in VPDPcdList:
- # Add BaseAddress for offset
- Offset = '0x%08X' % (int(item[2], 16) + self.VPDBaseAddress)
- IsByteArray, ArrayList = ByteArrayForamt(item[-1])
- Skuinfo = item[1]
- if len(GlobalData.gSkuids) == 1 :
- Skuinfo = GlobalData.gSkuids[0]
- if IsByteArray:
- FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], '{'))
- for Array in ArrayList:
- FileWrite(File, Array)
- else:
- FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], item[-1]))
- FileWrite(File, gSubSectionEnd)
- FileWrite(File, gSectionEnd)
-
-
-
-##
-# Reports platform information
-#
-# This class reports the whole platform information
-#
-class PlatformReport(object):
- ##
- # 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
- #
- def __init__(self, Wa, MaList, ReportType):
- self._WorkspaceDir = Wa.WorkspaceDir
- self.PlatformName = Wa.Name
- self.PlatformDscPath = Wa.Platform
- self.Architectures = " ".join(Wa.ArchList)
- self.ToolChain = Wa.ToolChain
- self.Target = Wa.BuildTarget
- self.OutputPath = os.path.join(Wa.WorkspaceDir, Wa.OutputDir)
- self.BuildEnvironment = platform.platform()
-
- self.PcdReport = None
- if "PCD" in ReportType:
- self.PcdReport = PcdReport(Wa)
-
- self.FdReportList = []
- if "FLASH" in ReportType and Wa.FdfProfile and MaList is None:
- for Fd in Wa.FdfProfile.FdDict:
- self.FdReportList.append(FdReport(Wa.FdfProfile.FdDict[Fd], Wa))
-
- self.PredictionReport = None
- if "FIXED_ADDRESS" in ReportType or "EXECUTION_ORDER" in ReportType:
- self.PredictionReport = PredictionReport(Wa)
-
- self.DepexParser = None
- if "DEPEX" in ReportType:
- self.DepexParser = DepexParser(Wa)
-
- self.ModuleReportList = []
- if MaList is not None:
- self._IsModuleBuild = True
- for Ma in MaList:
- self.ModuleReportList.append(ModuleReport(Ma, ReportType))
- else:
- self._IsModuleBuild = False
- for Pa in Wa.AutoGenObjectList:
- ModuleAutoGenList = []
- for ModuleKey in Pa.Platform.Modules:
- ModuleAutoGenList.append(Pa.Platform.Modules[ModuleKey].M)
- if GlobalData.gFdfParser is not None:
- if Pa.Arch in GlobalData.gFdfParser.Profile.InfDict:
- INFList = GlobalData.gFdfParser.Profile.InfDict[Pa.Arch]
- for InfName in INFList:
- InfClass = PathClass(NormPath(InfName), Wa.WorkspaceDir, Pa.Arch)
- Ma = ModuleAutoGen(Wa, InfClass, Pa.BuildTarget, Pa.ToolChain, Pa.Arch, Wa.MetaFile, Pa.DataPipe)
- if Ma is None:
- continue
- if Ma not in ModuleAutoGenList:
- ModuleAutoGenList.append(Ma)
- for MGen in ModuleAutoGenList:
- self.ModuleReportList.append(ModuleReport(MGen, ReportType))
-
-
-
- ##
- # 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 AutoGenTime The total time of AutoGen Phase
- # @param MakeTime The total time of Make Phase
- # @param GenFdsTime The total time of GenFds Phase
- # @param ReportType The kind of report items in the final report file
- #
- def GenerateReport(self, File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, ReportType):
- FileWrite(File, "Platform Summary")
- FileWrite(File, "Platform Name: %s" % self.PlatformName)
- FileWrite(File, "Platform DSC Path: %s" % self.PlatformDscPath)
- FileWrite(File, "Architectures: %s" % self.Architectures)
- FileWrite(File, "Tool Chain: %s" % self.ToolChain)
- FileWrite(File, "Target: %s" % self.Target)
- if GlobalData.gSkuids:
- FileWrite(File, "SKUID: %s" % " ".join(GlobalData.gSkuids))
- if GlobalData.gDefaultStores:
- FileWrite(File, "DefaultStore: %s" % " ".join(GlobalData.gDefaultStores))
- FileWrite(File, "Output Path: %s" % self.OutputPath)
- FileWrite(File, "Build Environment: %s" % self.BuildEnvironment)
- FileWrite(File, "Build Duration: %s" % BuildDuration)
- if AutoGenTime:
- FileWrite(File, "AutoGen Duration: %s" % AutoGenTime)
- if MakeTime:
- FileWrite(File, "Make Duration: %s" % MakeTime)
- if GenFdsTime:
- FileWrite(File, "GenFds Duration: %s" % GenFdsTime)
- FileWrite(File, "Report Content: %s" % ", ".join(ReportType))
-
- if GlobalData.MixedPcd:
- FileWrite(File, gSectionStart)
- FileWrite(File, "The following PCDs use different access methods:")
- FileWrite(File, gSectionSep)
- for PcdItem in GlobalData.MixedPcd:
- FileWrite(File, "%s.%s" % (str(PcdItem[1]), str(PcdItem[0])))
- FileWrite(File, gSectionEnd)
-
- if not self._IsModuleBuild:
- if "PCD" in ReportType:
- self.PcdReport.GenerateReport(File, None)
-
- if "FLASH" in ReportType:
- for FdReportListItem in self.FdReportList:
- FdReportListItem.GenerateReport(File)
-
- for ModuleReportItem in self.ModuleReportList:
- ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, self.DepexParser, ReportType)
-
- if not self._IsModuleBuild:
- if "EXECUTION_ORDER" in ReportType:
- self.PredictionReport.GenerateReport(File, None)
-
-## BuildReport class
-#
-# This base class contain the routines to collect data and then
-# applies certain format to the output report
-#
-class BuildReport(object):
- ##
- # 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
- #
- def __init__(self, ReportFile, ReportType):
- self.ReportFile = ReportFile
- if ReportFile:
- self.ReportList = []
- self.ReportType = []
- if ReportType:
- for ReportTypeItem in ReportType:
- if ReportTypeItem not in self.ReportType:
- self.ReportType.append(ReportTypeItem)
- else:
- self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
- ##
- # 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
- #
- def AddPlatformReport(self, Wa, MaList=None):
- if self.ReportFile:
- self.ReportList.append((Wa, MaList))
-
- ##
- # 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
- # @param AutoGenTime The total time of AutoGen phase
- # @param MakeTime The total time of Make phase
- # @param GenFdsTime The total time of GenFds phase
- #
- def GenerateReport(self, BuildDuration, AutoGenTime, MakeTime, GenFdsTime):
- if self.ReportFile:
- try:
-
- if "COMPILE_INFO" in self.ReportType:
- self.GenerateCompileInfo()
-
- File = []
- for (Wa, MaList) in self.ReportList:
- PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, self.ReportType)
- Content = FileLinesSplit(''.join(File), gLineMaxLength)
- SaveFileOnChange(self.ReportFile, Content, False)
- EdkLogger.quiet("Build report can be found at %s" % os.path.abspath(self.ReportFile))
- except IOError:
- EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)
- 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()))
-
-
- ##
- # Generates compile data files to be used by external tools.
- # Compile information will be generated in <Build>/<BuildTarget>/<ToolChain>/CompileInfo
- # Files generated: compile_commands.json, cscope.files, modules_report.json
- #
- # @param self The object pointer
- #
- def GenerateCompileInfo(self):
- try:
- # Lists for the output elements
- compile_commands = []
- used_files = set()
- module_report = []
-
- for (Wa, MaList) in self.ReportList:
- # Obtain list of all processed Workspace files
- for file_path in Wa._GetMetaFiles(Wa.BuildTarget, Wa.ToolChain):
- used_files.add(file_path)
-
- for autoGen in Wa.AutoGenObjectList:
-
- # Loop through all modules
- for module in (autoGen.LibraryAutoGenList + autoGen.ModuleAutoGenList):
-
- used_files.add(module.MetaFile.Path)
-
- # Main elements of module report
- module_report_data = {}
- module_report_data["Name"] = module.Name
- module_report_data["Arch"] = module.Arch
- module_report_data["Path"] = module.MetaFile.Path
- module_report_data["Guid"] = module.Guid
- module_report_data["BuildType"] = module.BuildType
- module_report_data["IsLibrary"] = module.IsLibrary
- module_report_data["SourceDir"] = module.SourceDir
- module_report_data["Files"] = []
- module_report_data["LibraryClass"] = module.Module.LibraryClass
- module_report_data["ModuleEntryPointList"] = module.Module.ModuleEntryPointList
- module_report_data["ConstructorList"] = module.Module.ConstructorList
- module_report_data["DestructorList"] = module.Module.DestructorList
-
- # Files used by module
- for data_file in module.SourceFileList:
- module_report_data["Files"].append({"Name": data_file.Name, "Path": data_file.Path})
-
- # Libraries used by module
- module_report_data["Libraries"] = []
- for data_library in module.LibraryAutoGenList:
- module_report_data["Libraries"].append({"Path": data_library.MetaFile.Path})
-
- # Packages used by module
- module_report_data["Packages"] = []
- for data_package in module.PackageList:
- module_report_data["Packages"].append({"Path": data_package.MetaFile.Path, "Includes": []})
- # Includes path used in package
- for data_package_include in data_package.Includes:
- module_report_data["Packages"][-1]["Includes"].append(data_package_include.Path)
-
- # PPI's in module
- module_report_data["PPI"] = []
- for data_ppi in module.PpiList.keys():
- module_report_data["PPI"].append({"Name": data_ppi, "Guid": module.PpiList[data_ppi]})
-
- # Protocol's in module
- module_report_data["Protocol"] = []
- for data_protocol in module.ProtocolList.keys():
- module_report_data["Protocol"].append({"Name": data_protocol, "Guid": module.ProtocolList[data_protocol]})
-
- # PCD's in module
- module_report_data["Pcd"] = []
- for data_pcd in module.LibraryPcdList:
- module_report_data["Pcd"].append({"Space": data_pcd.TokenSpaceGuidCName,
- "Name": data_pcd.TokenCName,
- "Value": data_pcd.TokenValue,
- "Guid": data_pcd.TokenSpaceGuidValue,
- "DatumType": data_pcd.DatumType,
- "Type": data_pcd.Type,
- "DefaultValue": data_pcd.DefaultValue})
- # Add module to report
- module_report.append(module_report_data)
-
- # Include file dependencies to used files
- includes_autogen = IncludesAutoGen(module.MakeFileDir, module)
- for dep in includes_autogen.DepsCollection:
- used_files.add(dep)
-
- inc_flag = "-I" # Default include flag
- if module.BuildRuleFamily == TAB_COMPILER_MSFT:
- inc_flag = "/I"
-
- for source in module.SourceFileList:
- used_files.add(source.Path)
- compile_command = {}
- if source.Ext in [".c", ".cc", ".cpp"]:
- #
- # Generate compile command for each c file
- #
- compile_command["file"] = source.Path
- compile_command["directory"] = source.Dir
- build_command = module.BuildRules[source.Ext].CommandList[0]
- build_command_variables = re.findall(r"\$\((.*?)\)", build_command)
- for var in build_command_variables:
- var_tokens = var.split("_")
- var_main = var_tokens[0]
- if len(var_tokens) == 1:
- var_value = module.BuildOption[var_main]["PATH"]
- else:
- var_value = module.BuildOption[var_main][var_tokens[1]]
- build_command = build_command.replace(f"$({var})", var_value)
- include_files = f" {inc_flag}".join(module.IncludePathList)
- build_command = build_command.replace("${src}", include_files)
- build_command = build_command.replace("${dst}", module.OutputDir)
-
- # Remove un defined macros
- compile_command["command"] = re.sub(r"\$\(.*?\)", "", build_command)
- compile_commands.append(compile_command)
-
- # Create output folder if doesn't exist
- compile_info_folder = Path(Wa.BuildDir).joinpath("CompileInfo")
- compile_info_folder.mkdir(exist_ok=True)
-
- # Sort and save files
- compile_commands.sort(key=lambda x: x["file"])
- SaveFileOnChange(compile_info_folder.joinpath(f"compile_commands.json"),json.dumps(compile_commands, indent=2), False)
-
- SaveFileOnChange(compile_info_folder.joinpath(f"cscope.files"), "\n".join(sorted(used_files)), False)
-
- module_report.sort(key=lambda x: x["Path"])
- SaveFileOnChange(compile_info_folder.joinpath(f"module_report.json"), json.dumps(module_report, indent=2), False)
-
- except:
- EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report compile information", 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
+## @file
+# Routines for generating build report.
+#
+# This module contains the functionality to generate build report after
+# build all target completes successfully.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+## Import Modules
+#
+import json
+from pathlib import Path
+import Common.LongFilePathOs as os
+import re
+import platform
+import textwrap
+import traceback
+import sys
+import time
+import struct
+import hashlib
+import subprocess
+import threading
+from datetime import datetime
+from io import BytesIO
+from Common import EdkLogger
+from Common.Misc import SaveFileOnChange
+from Common.Misc import GuidStructureByteArrayToGuidString
+from Common.Misc import GuidStructureStringToGuidString
+from Common.BuildToolError import FILE_WRITE_FAILURE
+from Common.BuildToolError import CODE_ERROR
+from Common.BuildToolError import COMMAND_FAILURE
+from Common.BuildToolError import FORMAT_INVALID
+from Common.LongFilePathSupport import OpenLongFilePath as open
+from Common.MultipleWorkspace import MultipleWorkspace as mws
+import Common.GlobalData as GlobalData
+from AutoGen.ModuleAutoGen import ModuleAutoGen
+from Common.Misc import PathClass
+from Common.StringUtils import NormPath
+from Common.DataType import *
+import collections
+from Common.Expression import *
+from GenFds.AprioriSection import DXE_APRIORI_GUID, PEI_APRIORI_GUID
+from AutoGen.IncludesAutoGen import IncludesAutoGen
+
+## Pattern to extract contents in EDK DXS files
+gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)
+
+## Pattern to find total FV total size, occupied size in flash report intermediate file
+gFvTotalSizePattern = re.compile(r"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
+gFvTakenSizePattern = re.compile(r"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
+
+## Pattern to find module size and time stamp in module summary report intermediate file
+gModuleSizePattern = re.compile(r"MODULE_SIZE = (\d+)")
+gTimeStampPattern = re.compile(r"TIME_STAMP = (\d+)")
+
+## Pattern to find GUID value in flash description files
+gPcdGuidPattern = re.compile(r"PCD\((\w+)[.](\w+)\)")
+
+## Pattern to collect offset, GUID value pair in the flash report intermediate file
+gOffsetGuidPattern = re.compile(r"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
+
+## 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*Type=\w+\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
+gMapFileItemPattern = re.compile(gModulePattern % {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
+
+## Pattern to find all module referenced header files in source files
+gIncludePattern = re.compile(r'#include\s*["<]([^">]+)[">]')
+gIncludePattern2 = re.compile(r"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
+
+## Pattern to find the entry point for EDK module using EDKII Glue library
+gGlueLibEntryPoint = re.compile(r"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
+
+## Tags for MaxLength of line in report
+gLineMaxLength = 120
+
+## Tags for end of line in report
+gEndOfLine = "\r\n"
+
+## Tags for section start, end and separator
+gSectionStart = ">" + "=" * (gLineMaxLength - 2) + "<"
+gSectionEnd = "<" + "=" * (gLineMaxLength - 2) + ">" + "\n"
+gSectionSep = "=" * gLineMaxLength
+
+## Tags for subsection start, end and separator
+gSubSectionStart = ">" + "-" * (gLineMaxLength - 2) + "<"
+gSubSectionEnd = "<" + "-" * (gLineMaxLength - 2) + ">"
+gSubSectionSep = "-" * gLineMaxLength
+
+
+## The look up table to map PCD type to pair of report display type and DEC type
+gPcdTypeMap = {
+ TAB_PCDS_FIXED_AT_BUILD : ('FIXED', TAB_PCDS_FIXED_AT_BUILD),
+ TAB_PCDS_PATCHABLE_IN_MODULE: ('PATCH', TAB_PCDS_PATCHABLE_IN_MODULE),
+ TAB_PCDS_FEATURE_FLAG : ('FLAG', TAB_PCDS_FEATURE_FLAG),
+ TAB_PCDS_DYNAMIC : ('DYN', TAB_PCDS_DYNAMIC),
+ TAB_PCDS_DYNAMIC_HII : ('DYNHII', TAB_PCDS_DYNAMIC),
+ TAB_PCDS_DYNAMIC_VPD : ('DYNVPD', TAB_PCDS_DYNAMIC),
+ TAB_PCDS_DYNAMIC_EX : ('DEX', TAB_PCDS_DYNAMIC_EX),
+ TAB_PCDS_DYNAMIC_EX_HII : ('DEXHII', TAB_PCDS_DYNAMIC_EX),
+ TAB_PCDS_DYNAMIC_EX_VPD : ('DEXVPD', TAB_PCDS_DYNAMIC_EX),
+ }
+
+## The look up table to map module type to driver type
+gDriverTypeMap = {
+ SUP_MODULE_SEC : '0x3 (SECURITY_CORE)',
+ SUP_MODULE_PEI_CORE : '0x4 (PEI_CORE)',
+ SUP_MODULE_PEIM : '0x6 (PEIM)',
+ SUP_MODULE_DXE_CORE : '0x5 (DXE_CORE)',
+ SUP_MODULE_DXE_DRIVER : '0x7 (DRIVER)',
+ SUP_MODULE_DXE_SAL_DRIVER : '0x7 (DRIVER)',
+ SUP_MODULE_DXE_SMM_DRIVER : '0x7 (DRIVER)',
+ SUP_MODULE_DXE_RUNTIME_DRIVER: '0x7 (DRIVER)',
+ SUP_MODULE_UEFI_DRIVER : '0x7 (DRIVER)',
+ SUP_MODULE_UEFI_APPLICATION : '0x9 (APPLICATION)',
+ SUP_MODULE_SMM_CORE : '0xD (SMM_CORE)',
+ 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
+ SUP_MODULE_MM_STANDALONE : '0xE (MM_STANDALONE)',
+ SUP_MODULE_MM_CORE_STANDALONE : '0xF (MM_CORE_STANDALONE)'
+ }
+
+## The look up table of the supported opcode in the dependency expression binaries
+gOpCodeList = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
+
+## Save VPD Pcd
+VPDPcdList = []
+
+##
+# 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
+#
+def FileWrite(File, String, Wrapper=False):
+ if Wrapper:
+ String = textwrap.fill(String, 120)
+ File.append(String + gEndOfLine)
+
+def ByteArrayForamt(Value):
+ IsByteArray = False
+ SplitNum = 16
+ ArrayList = []
+ if Value.startswith('{') and Value.endswith('}') and not Value.startswith("{CODE("):
+ Value = Value[1:-1]
+ ValueList = Value.split(',')
+ if len(ValueList) >= SplitNum:
+ IsByteArray = True
+ if IsByteArray:
+ if ValueList:
+ Len = len(ValueList)/SplitNum
+ for i, element in enumerate(ValueList):
+ ValueList[i] = '0x%02X' % int(element.strip(), 16)
+ if Len:
+ Id = 0
+ while (Id <= Len):
+ End = min(SplitNum*(Id+1), len(ValueList))
+ Str = ','.join(ValueList[SplitNum*Id : End])
+ if End == len(ValueList):
+ Str += '}'
+ ArrayList.append(Str)
+ break
+ else:
+ Str += ','
+ ArrayList.append(Str)
+ Id += 1
+ else:
+ ArrayList = [Value + '}']
+ return IsByteArray, ArrayList
+
+##
+# 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.
+#
+def FindIncludeFiles(Source, IncludePathList, IncludeFiles):
+ FileContents = open(Source).read()
+ #
+ # Find header files with pattern #include "XXX.h" or #include <XXX.h>
+ #
+ for Match in gIncludePattern.finditer(FileContents):
+ FileName = Match.group(1).strip()
+ for Dir in [os.path.dirname(Source)] + IncludePathList:
+ FullFileName = os.path.normpath(os.path.join(Dir, FileName))
+ if os.path.exists(FullFileName):
+ IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName
+ break
+
+ #
+ # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
+ #
+ for Match in gIncludePattern2.finditer(FileContents):
+ Key = Match.group(2)
+ Type = Match.group(1)
+ if "ARCH_PROTOCOL" in Type:
+ FileName = "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key}
+ elif "PROTOCOL" in Type:
+ FileName = "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key}
+ elif "PPI" in Type:
+ FileName = "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key}
+ elif TAB_GUID in Type:
+ FileName = "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key}
+ else:
+ continue
+ for Dir in IncludePathList:
+ FullFileName = os.path.normpath(os.path.join(Dir, FileName))
+ if os.path.exists(FullFileName):
+ IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName
+ 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
+#
+def FileLinesSplit(Content=None, MaxLength=None):
+ ContentList = Content.split(TAB_LINE_BREAK)
+ NewContent = ''
+ NewContentList = []
+ for Line in ContentList:
+ while len(Line.rstrip()) > MaxLength:
+ LineSpaceIndex = Line.rfind(TAB_SPACE_SPLIT, 0, MaxLength)
+ LineSlashIndex = Line.rfind(TAB_SLASH, 0, MaxLength)
+ LineBackSlashIndex = Line.rfind(TAB_BACK_SLASH, 0, MaxLength)
+ if max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex) > 0:
+ LineBreakIndex = max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex)
+ else:
+ LineBreakIndex = MaxLength
+ NewContentList.append(Line[:LineBreakIndex])
+ Line = Line[LineBreakIndex:]
+ if Line:
+ NewContentList.append(Line)
+ for NewLine in NewContentList:
+ NewContent += NewLine + TAB_LINE_BREAK
+
+ NewContent = NewContent.replace(gEndOfLine, TAB_LINE_BREAK).replace('\r\r\n', gEndOfLine)
+ return NewContent
+
+
+
+##
+# Parse binary dependency expression section
+#
+# This utility class parses the dependency expression section and translate the readable
+# GUID name and value.
+#
+class DepexParser(object):
+ ##
+ # 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
+ #
+ def __init__(self, Wa):
+ self._GuidDb = {}
+ for Pa in Wa.AutoGenObjectList:
+ for Package in Pa.PackageList:
+ for Protocol in Package.Protocols:
+ GuidValue = GuidStructureStringToGuidString(Package.Protocols[Protocol])
+ self._GuidDb[GuidValue.upper()] = Protocol
+ for Ppi in Package.Ppis:
+ GuidValue = GuidStructureStringToGuidString(Package.Ppis[Ppi])
+ self._GuidDb[GuidValue.upper()] = Ppi
+ for Guid in Package.Guids:
+ GuidValue = GuidStructureStringToGuidString(Package.Guids[Guid])
+ self._GuidDb[GuidValue.upper()] = Guid
+ for Ma in Pa.ModuleAutoGenList:
+ for Pcd in Ma.FixedVoidTypePcds:
+ PcdValue = Ma.FixedVoidTypePcds[Pcd]
+ if len(PcdValue.split(',')) == 16:
+ GuidValue = GuidStructureByteArrayToGuidString(PcdValue)
+ self._GuidDb[GuidValue.upper()] = Pcd
+ ##
+ # 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.
+ #
+ def ParseDepexFile(self, DepexFileName):
+ DepexFile = open(DepexFileName, "rb")
+ DepexStatement = []
+ OpCode = DepexFile.read(1)
+ while OpCode:
+ Statement = gOpCodeList[struct.unpack("B", OpCode)[0]]
+ if Statement in ["BEFORE", "AFTER", "PUSH"]:
+ GuidValue = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
+ struct.unpack(PACK_PATTERN_GUID, DepexFile.read(16))
+ GuidString = self._GuidDb.get(GuidValue, GuidValue)
+ Statement = "%s %s" % (Statement, GuidString)
+ DepexStatement.append(Statement)
+ OpCode = DepexFile.read(1)
+
+ return DepexStatement
+
+##
+# Reports library information
+#
+# This class reports the module library subsection in the build report file.
+#
+class LibraryReport(object):
+ ##
+ # Constructor function for class LibraryReport
+ #
+ # This constructor function generates LibraryReport object for
+ # a module.
+ #
+ # @param self The object pointer
+ # @param M Module context information
+ #
+ def __init__(self, M):
+ self.LibraryList = []
+
+ for Lib in M.DependentLibraryList:
+ LibInfPath = str(Lib)
+ LibClassList = Lib.LibraryClass[0].LibraryClass
+ LibConstructorList = Lib.ConstructorList
+ LibDesstructorList = Lib.DestructorList
+ LibDepexList = Lib.DepexExpression[M.Arch, M.ModuleType]
+ for LibAutoGen in M.LibraryAutoGenList:
+ if LibInfPath == LibAutoGen.MetaFile.Path:
+ LibTime = LibAutoGen.BuildTime
+ break
+ self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList, LibTime))
+
+ ##
+ # 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
+ #
+ def GenerateReport(self, File):
+ if len(self.LibraryList) > 0:
+ FileWrite(File, gSubSectionStart)
+ FileWrite(File, TAB_BRG_LIBRARY)
+ FileWrite(File, gSubSectionSep)
+ for LibraryItem in self.LibraryList:
+ LibInfPath = LibraryItem[0]
+ FileWrite(File, LibInfPath)
+
+ LibClass = LibraryItem[1]
+ EdkIILibInfo = ""
+ LibConstructor = " ".join(LibraryItem[2])
+ if LibConstructor:
+ EdkIILibInfo += " C = " + LibConstructor
+ LibDestructor = " ".join(LibraryItem[3])
+ if LibDestructor:
+ EdkIILibInfo += " D = " + LibDestructor
+ LibDepex = " ".join(LibraryItem[4])
+ if LibDepex:
+ EdkIILibInfo += " Depex = " + LibDepex
+ if LibraryItem[5]:
+ EdkIILibInfo += " Time = " + LibraryItem[5]
+ if EdkIILibInfo:
+ FileWrite(File, "{%s: %s}" % (LibClass, EdkIILibInfo))
+ else:
+ FileWrite(File, "{%s}" % LibClass)
+
+ FileWrite(File, gSubSectionEnd)
+
+##
+# Reports dependency expression information
+#
+# This class reports the module dependency expression subsection in the build report file.
+#
+class DepexReport(object):
+ ##
+ # 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
+ #
+ def __init__(self, M):
+ self.Depex = ""
+ self._DepexFileName = os.path.join(M.BuildDir, "OUTPUT", M.Module.BaseName + ".depex")
+ ModuleType = M.ModuleType
+ if not ModuleType:
+ ModuleType = COMPONENT_TO_MODULE_MAP_DICT.get(M.ComponentType, "")
+
+ if ModuleType in [SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_DXE_CORE, SUP_MODULE_SMM_CORE, SUP_MODULE_MM_CORE_STANDALONE, SUP_MODULE_UEFI_APPLICATION]:
+ return
+
+ for Source in M.SourceFileList:
+ if os.path.splitext(Source.Path)[1].lower() == ".dxs":
+ Match = gDxsDependencyPattern.search(open(Source.Path).read())
+ if Match:
+ self.Depex = Match.group(1).strip()
+ self.Source = "DXS"
+ break
+ else:
+ self.Depex = M.DepexExpressionDict.get(M.ModuleType, "")
+ self.ModuleDepex = " ".join(M.Module.DepexExpression[M.Arch, M.ModuleType])
+ if not self.ModuleDepex:
+ self.ModuleDepex = "(None)"
+
+ LibDepexList = []
+ for Lib in M.DependentLibraryList:
+ LibDepex = " ".join(Lib.DepexExpression[M.Arch, M.ModuleType]).strip()
+ if LibDepex != "":
+ LibDepexList.append("(" + LibDepex + ")")
+ self.LibraryDepex = " AND ".join(LibDepexList)
+ if not self.LibraryDepex:
+ self.LibraryDepex = "(None)"
+ self.Source = "INF"
+
+ ##
+ # 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
+ #
+ def GenerateReport(self, File, GlobalDepexParser):
+ if not self.Depex:
+ return
+ FileWrite(File, gSubSectionStart)
+ if os.path.isfile(self._DepexFileName):
+ try:
+ DepexStatements = GlobalDepexParser.ParseDepexFile(self._DepexFileName)
+ FileWrite(File, "Final Dependency Expression (DEPEX) Instructions")
+ for DepexStatement in DepexStatements:
+ FileWrite(File, " %s" % DepexStatement)
+ FileWrite(File, gSubSectionSep)
+ except:
+ EdkLogger.warn(None, "Dependency expression file is corrupted", self._DepexFileName)
+
+ FileWrite(File, "Dependency Expression (DEPEX) from %s" % self.Source)
+
+ if self.Source == "INF":
+ FileWrite(File, self.Depex, True)
+ FileWrite(File, gSubSectionSep)
+ FileWrite(File, "From Module INF: %s" % self.ModuleDepex, True)
+ FileWrite(File, "From Library INF: %s" % self.LibraryDepex, True)
+ else:
+ FileWrite(File, self.Depex)
+ FileWrite(File, gSubSectionEnd)
+
+##
+# Reports dependency expression information
+#
+# This class reports the module build flags subsection in the build report file.
+#
+class BuildFlagsReport(object):
+ ##
+ # 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
+ #
+ def __init__(self, M):
+ BuildOptions = {}
+ #
+ # Add build flags according to source file extension so that
+ # irrelevant ones can be filtered out.
+ #
+ for Source in M.SourceFileList:
+ Ext = os.path.splitext(Source.File)[1].lower()
+ if Ext in [".c", ".cc", ".cpp"]:
+ BuildOptions["CC"] = 1
+ elif Ext in [".s", ".asm"]:
+ BuildOptions["PP"] = 1
+ BuildOptions["ASM"] = 1
+ elif Ext in [".vfr"]:
+ BuildOptions["VFRPP"] = 1
+ BuildOptions["VFR"] = 1
+ elif Ext in [".dxs"]:
+ BuildOptions["APP"] = 1
+ BuildOptions["CC"] = 1
+ elif Ext in [".asl"]:
+ BuildOptions["ASLPP"] = 1
+ BuildOptions["ASL"] = 1
+ elif Ext in [".aslc"]:
+ BuildOptions["ASLCC"] = 1
+ BuildOptions["ASLDLINK"] = 1
+ BuildOptions["CC"] = 1
+ elif Ext in [".asm16"]:
+ BuildOptions["ASMLINK"] = 1
+ BuildOptions["SLINK"] = 1
+ BuildOptions["DLINK"] = 1
+
+ #
+ # Save module build flags.
+ #
+ self.ToolChainTag = M.ToolChain
+ self.BuildFlags = {}
+ for Tool in BuildOptions:
+ self.BuildFlags[Tool + "_FLAGS"] = M.BuildOption.get(Tool, {}).get("FLAGS", "")
+
+ ##
+ # 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
+ #
+ def GenerateReport(self, File):
+ FileWrite(File, gSubSectionStart)
+ FileWrite(File, "Build Flags")
+ FileWrite(File, "Tool Chain Tag: %s" % self.ToolChainTag)
+ for Tool in self.BuildFlags:
+ FileWrite(File, gSubSectionSep)
+ FileWrite(File, "%s = %s" % (Tool, self.BuildFlags[Tool]), True)
+
+ FileWrite(File, gSubSectionEnd)
+
+
+##
+# 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.
+#
+class ModuleReport(object):
+ ##
+ # 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
+ #
+ def __init__(self, M, ReportType):
+ self.ModuleName = M.Module.BaseName
+ self.ModuleInfPath = M.MetaFile.File
+ self.ModuleArch = M.Arch
+ self.FileGuid = M.Guid
+ self.Size = 0
+ self.BuildTimeStamp = None
+ self.Hash = 0
+ self.DriverType = ""
+ if not M.IsLibrary:
+ ModuleType = M.ModuleType
+ if not ModuleType:
+ ModuleType = COMPONENT_TO_MODULE_MAP_DICT.get(M.ComponentType, "")
+ #
+ # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
+ #
+ if ModuleType == SUP_MODULE_DXE_SMM_DRIVER:
+ PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000")
+ if int(PiSpec, 0) >= 0x0001000A:
+ ModuleType = "SMM_DRIVER"
+ self.DriverType = gDriverTypeMap.get(ModuleType, "0x2 (FREE_FORM)")
+ self.UefiSpecVersion = M.Module.Specification.get("UEFI_SPECIFICATION_VERSION", "")
+ self.PiSpecVersion = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "")
+ self.PciDeviceId = M.Module.Defines.get("PCI_DEVICE_ID", "")
+ self.PciVendorId = M.Module.Defines.get("PCI_VENDOR_ID", "")
+ self.PciClassCode = M.Module.Defines.get("PCI_CLASS_CODE", "")
+ self.BuildTime = M.BuildTime
+
+ self._BuildDir = M.BuildDir
+ 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.
+ #
+ for Pcd in M.ModulePcdList + M.LibraryPcdList:
+ self.ModulePcdSet.setdefault((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Type), (Pcd.InfDefaultValue, Pcd.DefaultValue))
+
+ self.LibraryReport = None
+ if "LIBRARY" in ReportType:
+ self.LibraryReport = LibraryReport(M)
+
+ self.DepexReport = None
+ if "DEPEX" in ReportType:
+ self.DepexReport = DepexReport(M)
+
+ if "BUILD_FLAGS" in ReportType:
+ self.BuildFlagsReport = BuildFlagsReport(M)
+
+
+ ##
+ # 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):
+ FileWrite(File, gSectionStart)
+
+ FwReportFileName = os.path.join(self._BuildDir, "OUTPUT", self.ModuleName + ".txt")
+ if os.path.isfile(FwReportFileName):
+ try:
+ FileContents = open(FwReportFileName).read()
+ Match = gModuleSizePattern.search(FileContents)
+ if Match:
+ self.Size = int(Match.group(1))
+
+ Match = gTimeStampPattern.search(FileContents)
+ if Match:
+ self.BuildTimeStamp = datetime.utcfromtimestamp(int(Match.group(1)))
+ except IOError:
+ EdkLogger.warn(None, "Fail to read report file", FwReportFileName)
+
+ if "HASH" in ReportType:
+ OutputDir = os.path.join(self._BuildDir, "OUTPUT")
+ DefaultEFIfile = os.path.join(OutputDir, self.ModuleName + ".efi")
+ if os.path.isfile(DefaultEFIfile):
+ Tempfile = os.path.join(OutputDir, self.ModuleName + "_hash.tmp")
+ # rebase the efi image since its base address may not zero
+ cmd = ["GenFw", "--rebase", str(0), "-o", Tempfile, DefaultEFIfile]
+ try:
+ PopenObject = subprocess.Popen(' '.join(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+ except Exception as X:
+ EdkLogger.error("GenFw", COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0]))
+ EndOfProcedure = threading.Event()
+ EndOfProcedure.clear()
+ if PopenObject.stderr:
+ StdErrThread = threading.Thread(target=ReadMessage, args=(PopenObject.stderr, EdkLogger.quiet, EndOfProcedure))
+ StdErrThread.setName("STDERR-Redirector")
+ StdErrThread.setDaemon(False)
+ StdErrThread.start()
+ # waiting for program exit
+ PopenObject.wait()
+ if PopenObject.stderr:
+ StdErrThread.join()
+ if PopenObject.returncode != 0:
+ EdkLogger.error("GenFw", COMMAND_FAILURE, "Failed to generate firmware hash image for %s" % (DefaultEFIfile))
+ if os.path.isfile(Tempfile):
+ self.Hash = hashlib.sha1()
+ buf = open(Tempfile, 'rb').read()
+ if self.Hash.update(buf):
+ self.Hash = self.Hash.update(buf)
+ self.Hash = self.Hash.hexdigest()
+ os.remove(Tempfile)
+
+ FileWrite(File, "Module Summary")
+ FileWrite(File, "Module Name: %s" % self.ModuleName)
+ FileWrite(File, "Module Arch: %s" % self.ModuleArch)
+ FileWrite(File, "Module INF Path: %s" % self.ModuleInfPath)
+ FileWrite(File, "File GUID: %s" % self.FileGuid)
+ if self.Size:
+ FileWrite(File, "Size: 0x%X (%.2fK)" % (self.Size, self.Size / 1024.0))
+ if self.Hash:
+ FileWrite(File, "SHA1 HASH: %s *%s" % (self.Hash, self.ModuleName + ".efi"))
+ if self.BuildTimeStamp:
+ FileWrite(File, "Build Time Stamp: %s" % self.BuildTimeStamp)
+ if self.BuildTime:
+ FileWrite(File, "Module Build Time: %s" % self.BuildTime)
+ if self.DriverType:
+ FileWrite(File, "Driver Type: %s" % self.DriverType)
+ if self.UefiSpecVersion:
+ FileWrite(File, "UEFI Spec Version: %s" % self.UefiSpecVersion)
+ if self.PiSpecVersion:
+ FileWrite(File, "PI Spec Version: %s" % self.PiSpecVersion)
+ if self.PciDeviceId:
+ FileWrite(File, "PCI Device ID: %s" % self.PciDeviceId)
+ if self.PciVendorId:
+ FileWrite(File, "PCI Vendor ID: %s" % self.PciVendorId)
+ if self.PciClassCode:
+ FileWrite(File, "PCI Class Code: %s" % self.PciClassCode)
+
+ FileWrite(File, gSectionSep)
+
+ if "PCD" in ReportType:
+ GlobalPcdReport.GenerateReport(File, self.ModulePcdSet,self.FileGuid)
+
+ if "LIBRARY" in ReportType:
+ self.LibraryReport.GenerateReport(File)
+
+ if "DEPEX" in ReportType:
+ self.DepexReport.GenerateReport(File, GlobalDepexParser)
+
+ if "BUILD_FLAGS" in ReportType:
+ self.BuildFlagsReport.GenerateReport(File)
+
+ if "FIXED_ADDRESS" in ReportType and self.FileGuid:
+ GlobalPredictionReport.GenerateReport(File, self.FileGuid)
+
+ FileWrite(File, gSectionEnd)
+
+def ReadMessage(From, To, ExitFlag):
+ while True:
+ # read one line a time
+ Line = From.readline()
+ # empty string means "end"
+ if Line is not None and Line != b"":
+ To(Line.rstrip().decode(encoding='utf-8', errors='ignore'))
+ else:
+ break
+ if ExitFlag.isSet():
+ break
+
+##
+# Reports platform and module PCD information
+#
+# This class reports the platform PCD section and module PCD subsection
+# in the build report file.
+#
+class PcdReport(object):
+ ##
+ # 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
+ #
+ def __init__(self, Wa):
+ self.AllPcds = {}
+ self.UnusedPcds = {}
+ self.ConditionalPcds = {}
+ self.MaxLen = 0
+ self.Arch = None
+ if Wa.FdfProfile:
+ self.FdfPcdSet = Wa.FdfProfile.PcdDict
+ else:
+ self.FdfPcdSet = {}
+
+ self.DefaultStoreSingle = True
+ self.SkuSingle = True
+ if GlobalData.gDefaultStores and len(GlobalData.gDefaultStores) > 1:
+ self.DefaultStoreSingle = False
+ if GlobalData.gSkuids and len(GlobalData.gSkuids) > 1:
+ self.SkuSingle = False
+
+ self.ModulePcdOverride = {}
+ for Pa in Wa.AutoGenObjectList:
+ self.Arch = Pa.Arch
+ #
+ # Collect all platform referenced PCDs and grouped them by PCD token space
+ # GUID C Names
+ #
+ for Pcd in Pa.AllPcdList:
+ PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
+ if Pcd not in PcdList:
+ PcdList.append(Pcd)
+ if len(Pcd.TokenCName) > self.MaxLen:
+ self.MaxLen = len(Pcd.TokenCName)
+ #
+ # Collect the PCD defined in DSC/FDF file, but not used in module
+ #
+ UnusedPcdFullList = []
+ StructPcdDict = GlobalData.gStructurePcd.get(self.Arch, collections.OrderedDict())
+ for Name, Guid in StructPcdDict:
+ if (Name, Guid) not in Pa.Platform.Pcds:
+ Pcd = StructPcdDict[(Name, Guid)]
+ PcdList = self.AllPcds.setdefault(Guid, {}).setdefault(Pcd.Type, [])
+ if Pcd not in PcdList and Pcd not in UnusedPcdFullList:
+ UnusedPcdFullList.append(Pcd)
+ for item in Pa.Platform.Pcds:
+ Pcd = Pa.Platform.Pcds[item]
+ if not Pcd.Type:
+ # check the Pcd in FDF file, whether it is used in module first
+ for T in PCD_TYPE_LIST:
+ PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(T, [])
+ if Pcd in PcdList:
+ Pcd.Type = T
+ break
+ if not Pcd.Type:
+ PcdTypeFlag = False
+ for package in Pa.PackageList:
+ for T in PCD_TYPE_LIST:
+ if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T) in package.Pcds:
+ Pcd.Type = T
+ PcdTypeFlag = True
+ if not Pcd.DatumType:
+ Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T)].DatumType
+ break
+ if PcdTypeFlag:
+ break
+ if not Pcd.DatumType:
+ PcdType = Pcd.Type
+ # Try to remove Hii and Vpd suffix
+ if PcdType.startswith(TAB_PCDS_DYNAMIC_EX):
+ PcdType = TAB_PCDS_DYNAMIC_EX
+ elif PcdType.startswith(TAB_PCDS_DYNAMIC):
+ PcdType = TAB_PCDS_DYNAMIC
+ for package in Pa.PackageList:
+ if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType) in package.Pcds:
+ Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType)].DatumType
+ break
+
+ PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
+ UnusedPcdList = self.UnusedPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
+ if Pcd in UnusedPcdList:
+ UnusedPcdList.remove(Pcd)
+ if Pcd not in PcdList and Pcd not in UnusedPcdFullList:
+ UnusedPcdFullList.append(Pcd)
+ if len(Pcd.TokenCName) > self.MaxLen:
+ self.MaxLen = len(Pcd.TokenCName)
+
+ if GlobalData.gConditionalPcds:
+ for PcdItem in GlobalData.gConditionalPcds:
+ if '.' in PcdItem:
+ (TokenSpaceGuidCName, TokenCName) = PcdItem.split('.')
+ if (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:
+ Pcd = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)]
+ PcdList = self.ConditionalPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
+ if Pcd not in PcdList:
+ PcdList.append(Pcd)
+
+ UnusedPcdList = []
+ if UnusedPcdFullList:
+ for Pcd in UnusedPcdFullList:
+ if Pcd.TokenSpaceGuidCName + '.' + Pcd.TokenCName in GlobalData.gConditionalPcds:
+ continue
+ UnusedPcdList.append(Pcd)
+
+ for Pcd in UnusedPcdList:
+ PcdList = self.UnusedPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])
+ if Pcd not in PcdList:
+ PcdList.append(Pcd)
+
+ for Module in Pa.Platform.Modules.values():
+ #
+ # Collect module override PCDs
+ #
+ for ModulePcd in Module.M.ModulePcdList + Module.M.LibraryPcdList:
+ TokenCName = ModulePcd.TokenCName
+ TokenSpaceGuid = ModulePcd.TokenSpaceGuidCName
+ ModuleDefault = ModulePcd.DefaultValue
+ ModulePath = os.path.basename(Module.M.MetaFile.File)
+ self.ModulePcdOverride.setdefault((TokenCName, TokenSpaceGuid), {})[ModulePath] = ModuleDefault
+
+
+ #
+ # Collect PCD DEC default value.
+ #
+ self.DecPcdDefault = {}
+ self._GuidDict = {}
+ for Pa in Wa.AutoGenObjectList:
+ for Package in Pa.PackageList:
+ Guids = Package.Guids
+ self._GuidDict.update(Guids)
+ for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:
+ DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue
+ self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)
+ #
+ # Collect PCDs defined in DSC common section
+ #
+ self.DscPcdDefault = {}
+ for Pa in Wa.AutoGenObjectList:
+ for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:
+ DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DscDefaultValue
+ if DscDefaultValue:
+ self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
+
+ def GenerateReport(self, File, ModulePcdSet,ModuleGuid=None):
+ if not ModulePcdSet:
+ if self.ConditionalPcds:
+ self.GenerateReportDetail(File, ModulePcdSet, 1)
+ if self.UnusedPcds:
+ IsEmpty = True
+ for Token in self.UnusedPcds:
+ TokenDict = self.UnusedPcds[Token]
+ for Type in TokenDict:
+ if TokenDict[Type]:
+ IsEmpty = False
+ break
+ if not IsEmpty:
+ break
+ if not IsEmpty:
+ self.GenerateReportDetail(File, ModulePcdSet, 2)
+ self.GenerateReportDetail(File, ModulePcdSet,ModuleGuid = ModuleGuid)
+
+ ##
+ # 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 ReportySubType 0 means platform/module PCD report, 1 means Conditional
+ # directives section report, 2 means Unused Pcds section report
+ # @param DscOverridePcds Module DSC override PCDs set
+ #
+ def GenerateReportDetail(self, File, ModulePcdSet, ReportSubType = 0,ModuleGuid=None):
+ PcdDict = self.AllPcds
+ if ReportSubType == 1:
+ PcdDict = self.ConditionalPcds
+ elif ReportSubType == 2:
+ PcdDict = self.UnusedPcds
+
+ if not ModulePcdSet:
+ FileWrite(File, gSectionStart)
+ if ReportSubType == 1:
+ FileWrite(File, "Conditional Directives used by the build system")
+ elif ReportSubType == 2:
+ FileWrite(File, "PCDs not used by modules or in conditional directives")
+ else:
+ FileWrite(File, "Platform Configuration Database Report")
+
+ FileWrite(File, " *B - PCD override in the build option")
+ FileWrite(File, " *P - Platform scoped PCD override in DSC file")
+ FileWrite(File, " *F - Platform scoped PCD override in FDF file")
+ if not ReportSubType:
+ FileWrite(File, " *M - Module scoped PCD override")
+ FileWrite(File, gSectionSep)
+ else:
+ if not ReportSubType and ModulePcdSet:
+ #
+ # For module PCD sub-section
+ #
+ FileWrite(File, gSubSectionStart)
+ FileWrite(File, TAB_BRG_PCD)
+ FileWrite(File, gSubSectionSep)
+ AllPcdDict = {}
+ for Key in PcdDict:
+ AllPcdDict[Key] = {}
+ for Type in PcdDict[Key]:
+ for Pcd in PcdDict[Key][Type]:
+ AllPcdDict[Key][(Pcd.TokenCName, Type)] = Pcd
+ for Key in sorted(AllPcdDict):
+ #
+ # Group PCD by their token space GUID C Name
+ #
+ First = True
+ for PcdTokenCName, Type in sorted(AllPcdDict[Key]):
+ #
+ # Group PCD by their usage type
+ #
+ Pcd = AllPcdDict[Key][(PcdTokenCName, Type)]
+ TypeName, DecType = gPcdTypeMap.get(Type, ("", Type))
+ MixedPcdFlag = False
+ if GlobalData.MixedPcd:
+ for PcdKey in GlobalData.MixedPcd:
+ if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdKey]:
+ PcdTokenCName = PcdKey[0]
+ MixedPcdFlag = True
+ if MixedPcdFlag and not ModulePcdSet:
+ continue
+ #
+ # Get PCD default value and their override relationship
+ #
+ DecDefaultValue = self.DecPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, DecType))
+ DscDefaultValue = self.DscPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))
+ DscDefaultValBak = DscDefaultValue
+ Field = ''
+ for (CName, Guid, Field) in self.FdfPcdSet:
+ if CName == PcdTokenCName and Guid == Key:
+ DscDefaultValue = self.FdfPcdSet[(CName, Guid, Field)]
+ break
+ if DscDefaultValue != DscDefaultValBak:
+ try:
+ DscDefaultValue = ValueExpressionEx(DscDefaultValue, Pcd.DatumType, self._GuidDict)(True)
+ except BadExpression as DscDefaultValue:
+ EdkLogger.error('BuildReport', FORMAT_INVALID, "PCD Value: %s, Type: %s" %(DscDefaultValue, Pcd.DatumType))
+
+ InfDefaultValue = None
+
+ PcdValue = DecDefaultValue
+ if DscDefaultValue:
+ PcdValue = DscDefaultValue
+ #The DefaultValue of StructurePcd already be the latest, no need to update.
+ if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
+ Pcd.DefaultValue = PcdValue
+ PcdComponentValue = None
+ if ModulePcdSet is not None:
+ if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type) not in ModulePcdSet:
+ continue
+ InfDefaultValue, PcdComponentValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]
+ PcdValue = PcdComponentValue
+ #The DefaultValue of StructurePcd already be the latest, no need to update.
+ if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
+ Pcd.DefaultValue = PcdValue
+ if InfDefaultValue:
+ try:
+ InfDefaultValue = ValueExpressionEx(InfDefaultValue, Pcd.DatumType, self._GuidDict)(True)
+ except BadExpression as InfDefaultValue:
+ EdkLogger.error('BuildReport', FORMAT_INVALID, "PCD Value: %s, Type: %s" % (InfDefaultValue, Pcd.DatumType))
+ if InfDefaultValue == "":
+ InfDefaultValue = None
+
+ BuildOptionMatch = False
+ if GlobalData.BuildOptionPcd:
+ for pcd in GlobalData.BuildOptionPcd:
+ if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) == (pcd[0], pcd[1]):
+ if pcd[2]:
+ continue
+ PcdValue = pcd[3]
+ #The DefaultValue of StructurePcd already be the latest, no need to update.
+ if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
+ Pcd.DefaultValue = PcdValue
+ BuildOptionMatch = True
+ break
+
+ if First:
+ if ModulePcdSet is None:
+ FileWrite(File, "")
+ FileWrite(File, Key)
+ First = False
+
+
+ if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:
+ if PcdValue.startswith('0') and not PcdValue.lower().startswith('0x') and \
+ len(PcdValue) > 1 and PcdValue.lstrip('0'):
+ PcdValue = PcdValue.lstrip('0')
+ PcdValueNumber = int(PcdValue.strip(), 0)
+ if DecDefaultValue is None:
+ DecMatch = True
+ else:
+ if DecDefaultValue.startswith('0') and not DecDefaultValue.lower().startswith('0x') and \
+ len(DecDefaultValue) > 1 and DecDefaultValue.lstrip('0'):
+ DecDefaultValue = DecDefaultValue.lstrip('0')
+ DecDefaultValueNumber = int(DecDefaultValue.strip(), 0)
+ DecMatch = (DecDefaultValueNumber == PcdValueNumber)
+
+ if InfDefaultValue is None:
+ InfMatch = True
+ else:
+ if InfDefaultValue.startswith('0') and not InfDefaultValue.lower().startswith('0x') and \
+ len(InfDefaultValue) > 1 and InfDefaultValue.lstrip('0'):
+ InfDefaultValue = InfDefaultValue.lstrip('0')
+ InfDefaultValueNumber = int(InfDefaultValue.strip(), 0)
+ InfMatch = (InfDefaultValueNumber == PcdValueNumber)
+
+ if DscDefaultValue is None:
+ DscMatch = True
+ else:
+ if DscDefaultValue.startswith('0') and not DscDefaultValue.lower().startswith('0x') and \
+ len(DscDefaultValue) > 1 and DscDefaultValue.lstrip('0'):
+ DscDefaultValue = DscDefaultValue.lstrip('0')
+ DscDefaultValueNumber = int(DscDefaultValue.strip(), 0)
+ DscMatch = (DscDefaultValueNumber == PcdValueNumber)
+ else:
+ if DecDefaultValue is None:
+ DecMatch = True
+ else:
+ DecMatch = (DecDefaultValue.strip() == PcdValue.strip())
+
+ if InfDefaultValue is None:
+ InfMatch = True
+ else:
+ InfMatch = (InfDefaultValue.strip() == PcdValue.strip())
+
+ if DscDefaultValue is None:
+ DscMatch = True
+ else:
+ DscMatch = (DscDefaultValue.strip() == PcdValue.strip())
+
+ IsStructure = False
+ if self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):
+ IsStructure = True
+ if TypeName in ('DYNVPD', 'DEXVPD'):
+ SkuInfoList = Pcd.SkuInfoList
+ Pcd = GlobalData.gStructurePcd[self.Arch][(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)]
+ if ModulePcdSet and ModulePcdSet.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type)):
+ InfDefaultValue, PcdComponentValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]
+ DscDefaultValBak = Pcd.DefaultValue
+ Pcd.DefaultValue = PcdComponentValue
+
+ Pcd.DatumType = Pcd.StructName
+ if TypeName in ('DYNVPD', 'DEXVPD'):
+ Pcd.SkuInfoList = SkuInfoList
+ if Pcd.PcdValueFromComm or Pcd.PcdFieldValueFromComm:
+ BuildOptionMatch = True
+ DecMatch = False
+ elif Pcd.PcdValueFromFdf or Pcd.PcdFieldValueFromFdf:
+ DscDefaultValue = True
+ DscMatch = True
+ DecMatch = False
+ else:
+ if Pcd.Type in PCD_DYNAMIC_TYPE_SET | PCD_DYNAMIC_EX_TYPE_SET:
+ DscOverride = False
+ if Pcd.DefaultFromDSC:
+ DscOverride = True
+ else:
+ DictLen = 0
+ for item in Pcd.SkuOverrideValues:
+ DictLen += len(Pcd.SkuOverrideValues[item])
+ if not DictLen:
+ DscOverride = False
+ else:
+ if not Pcd.SkuInfoList:
+ OverrideValues = Pcd.SkuOverrideValues
+ if OverrideValues:
+ for Data in OverrideValues.values():
+ Struct = list(Data.values())
+ if Struct:
+ DscOverride = self.ParseStruct(Struct[0])
+ break
+ else:
+ SkuList = sorted(Pcd.SkuInfoList.keys())
+ for Sku in SkuList:
+ SkuInfo = Pcd.SkuInfoList[Sku]
+ if SkuInfo.DefaultStoreDict:
+ DefaultStoreList = sorted(SkuInfo.DefaultStoreDict.keys())
+ for DefaultStore in DefaultStoreList:
+ OverrideValues = Pcd.SkuOverrideValues.get(Sku)
+ if OverrideValues:
+ DscOverride = self.ParseStruct(OverrideValues[DefaultStore])
+ if DscOverride:
+ break
+ if DscOverride:
+ break
+ if DscOverride:
+ DscDefaultValue = True
+ DscMatch = True
+ DecMatch = False
+ else:
+ DecMatch = True
+ else:
+ if Pcd.DscRawValue or (ModuleGuid and ModuleGuid.replace("-","S") in Pcd.PcdValueFromComponents):
+ DscDefaultValue = True
+ DscMatch = True
+ DecMatch = False
+ else:
+ DscDefaultValue = False
+ DecMatch = True
+
+ #
+ # Report PCD item according to their override relationship
+ #
+ if Pcd.DatumType == 'BOOLEAN':
+ if DscDefaultValue:
+ DscDefaultValue = str(int(DscDefaultValue, 0))
+ if DecDefaultValue:
+ DecDefaultValue = str(int(DecDefaultValue, 0))
+ if InfDefaultValue:
+ InfDefaultValue = str(int(InfDefaultValue, 0))
+ if Pcd.DefaultValue:
+ Pcd.DefaultValue = str(int(Pcd.DefaultValue, 0))
+ if DecMatch:
+ self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, ' ')
+ elif InfDefaultValue and InfMatch:
+ self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*M')
+ elif BuildOptionMatch:
+ self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*B')
+ else:
+ if PcdComponentValue:
+ self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, PcdComponentValue, DecMatch, DecDefaultValue, '*M', ModuleGuid)
+ elif DscDefaultValue and DscMatch:
+ if (Pcd.TokenCName, Key, Field) in self.FdfPcdSet:
+ self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*F')
+ else:
+ self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*P')
+
+
+ if ModulePcdSet is None:
+ if IsStructure:
+ continue
+ if not TypeName in ('PATCH', 'FLAG', 'FIXED'):
+ continue
+ if not BuildOptionMatch:
+ ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {})
+ for ModulePath in ModuleOverride:
+ ModuleDefault = ModuleOverride[ModulePath]
+ if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:
+ if ModuleDefault.startswith('0') and not ModuleDefault.lower().startswith('0x') and \
+ len(ModuleDefault) > 1 and ModuleDefault.lstrip('0'):
+ ModuleDefault = ModuleDefault.lstrip('0')
+ ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)
+ Match = (ModulePcdDefaultValueNumber == PcdValueNumber)
+ if Pcd.DatumType == 'BOOLEAN':
+ ModuleDefault = str(ModulePcdDefaultValueNumber)
+ else:
+ Match = (ModuleDefault.strip() == PcdValue.strip())
+ if Match:
+ continue
+ IsByteArray, ArrayList = ByteArrayForamt(ModuleDefault.strip())
+ if IsByteArray:
+ FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 15, ModulePath, '{'))
+ for Array in ArrayList:
+ FileWrite(File, Array)
+ else:
+ Value = ModuleDefault.strip()
+ if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
+ if Value.startswith(('0x', '0X')):
+ Value = '{} ({:d})'.format(Value, int(Value, 0))
+ else:
+ Value = "0x{:X} ({})".format(int(Value, 0), Value)
+ FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 15, ModulePath, Value))
+
+ if ModulePcdSet is None:
+ FileWrite(File, gSectionEnd)
+ else:
+ if not ReportSubType and ModulePcdSet:
+ FileWrite(File, gSubSectionEnd)
+
+ def ParseStruct(self, struct):
+ HasDscOverride = False
+ if struct:
+ for _, Values in list(struct.items()):
+ for Key, value in Values.items():
+ if value[1] and value[1].endswith('.dsc'):
+ HasDscOverride = True
+ break
+ if HasDscOverride == True:
+ break
+ return HasDscOverride
+
+ def PrintPcdDefault(self, File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue):
+ if not DscMatch and DscDefaultValue is not None:
+ Value = DscDefaultValue.strip()
+ IsByteArray, ArrayList = ByteArrayForamt(Value)
+ if IsByteArray:
+ FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', "{"))
+ for Array in ArrayList:
+ FileWrite(File, Array)
+ else:
+ if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
+ if Value.startswith(('0x', '0X')):
+ Value = '{} ({:d})'.format(Value, int(Value, 0))
+ else:
+ Value = "0x{:X} ({})".format(int(Value, 0), Value)
+ FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', Value))
+ if not InfMatch and InfDefaultValue is not None:
+ Value = InfDefaultValue.strip()
+ IsByteArray, ArrayList = ByteArrayForamt(Value)
+ if IsByteArray:
+ FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', "{"))
+ for Array in ArrayList:
+ FileWrite(File, Array)
+ else:
+ if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
+ if Value.startswith(('0x', '0X')):
+ Value = '{} ({:d})'.format(Value, int(Value, 0))
+ else:
+ Value = "0x{:X} ({})".format(int(Value, 0), Value)
+ FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', Value))
+
+ if not DecMatch and DecDefaultValue is not None:
+ Value = DecDefaultValue.strip()
+ IsByteArray, ArrayList = ByteArrayForamt(Value)
+ if IsByteArray:
+ FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', "{"))
+ for Array in ArrayList:
+ FileWrite(File, Array)
+ else:
+ if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
+ if Value.startswith(('0x', '0X')):
+ Value = '{} ({:d})'.format(Value, int(Value, 0))
+ else:
+ Value = "0x{:X} ({})".format(int(Value, 0), Value)
+ FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', Value))
+ if IsStructure:
+ for filedvalues in Pcd.DefaultValues.values():
+ self.PrintStructureInfo(File, filedvalues)
+ if DecMatch and IsStructure:
+ for filedvalues in Pcd.DefaultValues.values():
+ self.PrintStructureInfo(File, filedvalues)
+
+ def PrintPcdValue(self, File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, Flag = ' ',ModuleGuid=None):
+ if not Pcd.SkuInfoList:
+ Value = Pcd.DefaultValue
+ IsByteArray, ArrayList = ByteArrayForamt(Value)
+ if IsByteArray:
+ FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '{'))
+ for Array in ArrayList:
+ FileWrite(File, Array)
+ else:
+ if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
+ if Value.startswith('0') and not Value.lower().startswith('0x') and len(Value) > 1 and Value.lstrip('0'):
+ Value = Value.lstrip('0')
+ if Value.startswith(('0x', '0X')):
+ Value = '{} ({:d})'.format(Value, int(Value, 0))
+ else:
+ Value = "0x{:X} ({})".format(int(Value, 0), Value)
+ FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))
+ if IsStructure:
+ FiledOverrideFlag = False
+ if (Pcd.TokenCName,Pcd.TokenSpaceGuidCName) in GlobalData.gPcdSkuOverrides:
+ OverrideValues = GlobalData.gPcdSkuOverrides[(Pcd.TokenCName,Pcd.TokenSpaceGuidCName)]
+ else:
+ OverrideValues = Pcd.SkuOverrideValues
+ FieldOverrideValues = None
+ if OverrideValues:
+ for Data in OverrideValues.values():
+ Struct = list(Data.values())
+ if Struct:
+ FieldOverrideValues = Struct[0]
+ FiledOverrideFlag = True
+ break
+ if Pcd.PcdFiledValueFromDscComponent and ModuleGuid and ModuleGuid.replace("-","S") in Pcd.PcdFiledValueFromDscComponent:
+ FieldOverrideValues = Pcd.PcdFiledValueFromDscComponent[ModuleGuid.replace("-","S")]
+ if FieldOverrideValues:
+ OverrideFieldStruct = self.OverrideFieldValue(Pcd, FieldOverrideValues)
+ self.PrintStructureInfo(File, OverrideFieldStruct)
+
+ if not FiledOverrideFlag and (Pcd.PcdFieldValueFromComm or Pcd.PcdFieldValueFromFdf):
+ OverrideFieldStruct = self.OverrideFieldValue(Pcd, {})
+ self.PrintStructureInfo(File, OverrideFieldStruct)
+ self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)
+ else:
+ FirstPrint = True
+ SkuList = sorted(Pcd.SkuInfoList.keys())
+ for Sku in SkuList:
+ SkuInfo = Pcd.SkuInfoList[Sku]
+ SkuIdName = SkuInfo.SkuIdName
+ if TypeName in ('DYNHII', 'DEXHII'):
+ if SkuInfo.DefaultStoreDict:
+ DefaultStoreList = sorted(SkuInfo.DefaultStoreDict.keys())
+ for DefaultStore in DefaultStoreList:
+ Value = SkuInfo.DefaultStoreDict[DefaultStore]
+ IsByteArray, ArrayList = ByteArrayForamt(Value)
+ if Pcd.DatumType == 'BOOLEAN':
+ Value = str(int(Value, 0))
+ if FirstPrint:
+ FirstPrint = False
+ if IsByteArray:
+ if self.DefaultStoreSingle and self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '{'))
+ elif self.DefaultStoreSingle and not self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '{'))
+ elif not self.DefaultStoreSingle and self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', '{'))
+ else:
+ FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', '{'))
+ for Array in ArrayList:
+ FileWrite(File, Array)
+ else:
+ if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
+ if Value.startswith(('0x', '0X')):
+ Value = '{} ({:d})'.format(Value, int(Value, 0))
+ else:
+ Value = "0x{:X} ({})".format(int(Value, 0), Value)
+ if self.DefaultStoreSingle and self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))
+ elif self.DefaultStoreSingle and not self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
+ elif not self.DefaultStoreSingle and self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', Value))
+ else:
+ FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', Value))
+ else:
+ if IsByteArray:
+ if self.DefaultStoreSingle and self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '{'))
+ elif self.DefaultStoreSingle and not self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '{'))
+ elif not self.DefaultStoreSingle and self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', '{'))
+ else:
+ FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', '{'))
+ for Array in ArrayList:
+ FileWrite(File, Array)
+ else:
+ if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
+ if Value.startswith(('0x', '0X')):
+ Value = '{} ({:d})'.format(Value, int(Value, 0))
+ else:
+ Value = "0x{:X} ({})".format(int(Value, 0), Value)
+ if self.DefaultStoreSingle and self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', Value))
+ elif self.DefaultStoreSingle and not self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
+ elif not self.DefaultStoreSingle and self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', Value))
+ else:
+ FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', Value))
+ FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset))
+ if IsStructure:
+ OverrideValues = Pcd.SkuOverrideValues.get(Sku)
+ if OverrideValues:
+ OverrideFieldStruct = self.OverrideFieldValue(Pcd, OverrideValues[DefaultStore])
+ self.PrintStructureInfo(File, OverrideFieldStruct)
+ self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)
+ else:
+ Value = SkuInfo.DefaultValue
+ IsByteArray, ArrayList = ByteArrayForamt(Value)
+ if Pcd.DatumType == 'BOOLEAN':
+ Value = str(int(Value, 0))
+ if FirstPrint:
+ FirstPrint = False
+ if IsByteArray:
+ if self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', "{"))
+ else:
+ FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', "{"))
+ for Array in ArrayList:
+ FileWrite(File, Array)
+ else:
+ if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
+ if Value.startswith(('0x', '0X')):
+ Value = '{} ({:d})'.format(Value, int(Value, 0))
+ else:
+ Value = "0x{:X} ({})".format(int(Value, 0), Value)
+ if self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))
+ else:
+ FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
+ else:
+ if IsByteArray:
+ if self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', "{"))
+ else:
+ FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', "{"))
+ for Array in ArrayList:
+ FileWrite(File, Array)
+ else:
+ if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:
+ if Value.startswith(('0x', '0X')):
+ Value = '{} ({:d})'.format(Value, int(Value, 0))
+ else:
+ Value = "0x{:X} ({})".format(int(Value, 0), Value)
+ if self.SkuSingle:
+ FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', Value))
+ else:
+ FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))
+ if TypeName in ('DYNVPD', 'DEXVPD'):
+ FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset))
+ VPDPcdItem = (Pcd.TokenSpaceGuidCName + '.' + PcdTokenCName, SkuIdName, SkuInfo.VpdOffset, Pcd.MaxDatumSize, SkuInfo.DefaultValue)
+ if VPDPcdItem not in VPDPcdList:
+ PcdGuidList = self.UnusedPcds.get(Pcd.TokenSpaceGuidCName)
+ if PcdGuidList:
+ PcdList = PcdGuidList.get(Pcd.Type)
+ if not PcdList:
+ VPDPcdList.append(VPDPcdItem)
+ for VpdPcd in PcdList:
+ if PcdTokenCName == VpdPcd.TokenCName:
+ break
+ else:
+ VPDPcdList.append(VPDPcdItem)
+ if IsStructure:
+ FiledOverrideFlag = False
+ OverrideValues = Pcd.SkuOverrideValues.get(Sku)
+ if OverrideValues:
+ Keys = list(OverrideValues.keys())
+ OverrideFieldStruct = self.OverrideFieldValue(Pcd, OverrideValues[Keys[0]])
+ self.PrintStructureInfo(File, OverrideFieldStruct)
+ FiledOverrideFlag = True
+ if not FiledOverrideFlag and (Pcd.PcdFieldValueFromComm or Pcd.PcdFieldValueFromFdf):
+ OverrideFieldStruct = self.OverrideFieldValue(Pcd, {})
+ self.PrintStructureInfo(File, OverrideFieldStruct)
+ self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)
+
+ def OverrideFieldValue(self, Pcd, OverrideStruct):
+ OverrideFieldStruct = collections.OrderedDict()
+ if OverrideStruct:
+ for _, Values in OverrideStruct.items():
+ for Key,value in Values.items():
+ if value[1] and value[1].endswith('.dsc'):
+ OverrideFieldStruct[Key] = value
+ if Pcd.PcdFieldValueFromFdf:
+ for Key, Values in Pcd.PcdFieldValueFromFdf.items():
+ if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:
+ continue
+ OverrideFieldStruct[Key] = Values
+ if Pcd.PcdFieldValueFromComm:
+ for Key, Values in Pcd.PcdFieldValueFromComm.items():
+ if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:
+ continue
+ OverrideFieldStruct[Key] = Values
+ return OverrideFieldStruct
+
+ def PrintStructureInfo(self, File, Struct):
+ for Key, Value in sorted(Struct.items(), key=lambda x: x[0]):
+ if Value[1] and 'build command options' in Value[1]:
+ FileWrite(File, ' *B %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
+ elif Value[1] and Value[1].endswith('.fdf'):
+ FileWrite(File, ' *F %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
+ else:
+ FileWrite(File, ' %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
+
+ def StrtoHex(self, value):
+ try:
+ value = hex(int(value))
+ return value
+ except:
+ if value.startswith("L\"") and value.endswith("\""):
+ valuelist = []
+ for ch in value[2:-1]:
+ valuelist.append(hex(ord(ch)))
+ valuelist.append('0x00')
+ return valuelist
+ elif value.startswith("\"") and value.endswith("\""):
+ return hex(ord(value[1:-1]))
+ elif value.startswith("{") and value.endswith("}"):
+ valuelist = []
+ if ',' not in value:
+ return value[1:-1]
+ for ch in value[1:-1].split(','):
+ ch = ch.strip()
+ if ch.startswith('0x') or ch.startswith('0X'):
+ valuelist.append(ch)
+ continue
+ try:
+ valuelist.append(hex(int(ch.strip())))
+ except:
+ pass
+ return valuelist
+ else:
+ return value
+
+ def IsStructurePcd(self, PcdToken, PcdTokenSpaceGuid):
+ if GlobalData.gStructurePcd and (self.Arch in GlobalData.gStructurePcd) and ((PcdToken, PcdTokenSpaceGuid) in GlobalData.gStructurePcd[self.Arch]):
+ return True
+ else:
+ return False
+
+##
+# 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.
+#
+class PredictionReport(object):
+ ##
+ # Constructor function for class PredictionReport
+ #
+ # This constructor function generates PredictionReport object for the platform.
+ #
+ # @param self: The object pointer
+ # @param Wa Workspace context information
+ #
+ def __init__(self, Wa):
+ self._MapFileName = os.path.join(Wa.BuildDir, Wa.Name + ".map")
+ self._MapFileParsed = False
+ self._EotToolInvoked = False
+ self._FvDir = Wa.FvDir
+ self._EotDir = Wa.BuildDir
+ self._FfsEntryPoint = {}
+ self._GuidMap = {}
+ self._SourceList = []
+ self.FixedMapDict = {}
+ self.ItemList = []
+ self.MaxLen = 0
+
+ #
+ # Collect all platform reference source files and GUID C Name
+ #
+ for Pa in Wa.AutoGenObjectList:
+ for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList:
+ #
+ # BASE typed modules are EFI agnostic, so we need not scan
+ # their source code to find PPI/Protocol produce or consume
+ # information.
+ #
+ if Module.ModuleType == SUP_MODULE_BASE:
+ continue
+ #
+ # Add module referenced source files
+ #
+ self._SourceList.append(str(Module))
+ IncludeList = {}
+ for Source in Module.SourceFileList:
+ if os.path.splitext(str(Source))[1].lower() == ".c":
+ self._SourceList.append(" " + str(Source))
+ FindIncludeFiles(Source.Path, Module.IncludePathList, IncludeList)
+ for IncludeFile in IncludeList.values():
+ self._SourceList.append(" " + IncludeFile)
+
+ for Guid in Module.PpiList:
+ self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.PpiList[Guid])
+ for Guid in Module.ProtocolList:
+ self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.ProtocolList[Guid])
+ for Guid in Module.GuidList:
+ self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.GuidList[Guid])
+
+ if Module.Guid and not Module.IsLibrary:
+ EntryPoint = " ".join(Module.Module.ModuleEntryPointList)
+
+ RealEntryPoint = "_ModuleEntryPoint"
+
+ self._FfsEntryPoint[Module.Guid.upper()] = (EntryPoint, RealEntryPoint)
+
+
+ #
+ # Collect platform firmware volume list as the input of EOT.
+ #
+ self._FvList = []
+ if Wa.FdfProfile:
+ for Fd in Wa.FdfProfile.FdDict:
+ for FdRegion in Wa.FdfProfile.FdDict[Fd].RegionList:
+ if FdRegion.RegionType != BINARY_FILE_TYPE_FV:
+ continue
+ for FvName in FdRegion.RegionDataList:
+ if FvName in self._FvList:
+ continue
+ self._FvList.append(FvName)
+ for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
+ for Section in Ffs.SectionList:
+ try:
+ for FvSection in Section.SectionList:
+ if FvSection.FvName in self._FvList:
+ continue
+ self._FvList.append(FvSection.FvName)
+ 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
+ #
+ def _ParseMapFile(self):
+ if self._MapFileParsed:
+ return
+ self._MapFileParsed = True
+ if os.path.isfile(self._MapFileName):
+ try:
+ FileContents = open(self._MapFileName).read()
+ for Match in gMapFileItemPattern.finditer(FileContents):
+ AddressType = Match.group(1)
+ BaseAddress = Match.group(2)
+ EntryPoint = Match.group(3)
+ Guid = Match.group(4).upper()
+ List = self.FixedMapDict.setdefault(Guid, [])
+ List.append((AddressType, BaseAddress, "*I"))
+ List.append((AddressType, EntryPoint, "*E"))
+ except:
+ EdkLogger.warn(None, "Cannot open file to read", self._MapFileName)
+
+ ##
+ # 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
+ #
+ def _InvokeEotTool(self):
+ if self._EotToolInvoked:
+ return
+
+ self._EotToolInvoked = True
+ FvFileList = []
+ for FvName in self._FvList:
+ FvFile = os.path.join(self._FvDir, FvName + ".Fv")
+ if os.path.isfile(FvFile):
+ FvFileList.append(FvFile)
+
+ if len(FvFileList) == 0:
+ 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.
+ #
+ SourceList = os.path.join(self._EotDir, "SourceFile.txt")
+ GuidList = os.path.join(self._EotDir, "GuidList.txt")
+ DispatchList = os.path.join(self._EotDir, "Dispatch.txt")
+
+ TempFile = []
+ for Item in self._SourceList:
+ FileWrite(TempFile, Item)
+ SaveFileOnChange(SourceList, "".join(TempFile), False)
+ TempFile = []
+ for Key in self._GuidMap:
+ FileWrite(TempFile, "%s %s" % (Key, self._GuidMap[Key]))
+ SaveFileOnChange(GuidList, "".join(TempFile), False)
+
+ try:
+ from Eot.EotMain import Eot
+
+ #
+ # Invoke EOT tool and echo its runtime performance
+ #
+ EotStartTime = time.time()
+ Eot(CommandLineOption=False, SourceFileList=SourceList, GuidList=GuidList,
+ FvFileList=' '.join(FvFileList), Dispatch=DispatchList, IsInit=True)
+ EotEndTime = time.time()
+ EotDuration = time.strftime("%H:%M:%S", time.gmtime(int(round(EotEndTime - EotStartTime))))
+ EdkLogger.quiet("EOT run time: %s\n" % EotDuration)
+
+ #
+ # Parse the output of EOT tool
+ #
+ for Line in open(DispatchList):
+ if len(Line.split()) < 4:
+ continue
+ (Guid, Phase, FfsName, FilePath) = Line.split()
+ Symbol = self._FfsEntryPoint.get(Guid, [FfsName, ""])[0]
+ if len(Symbol) > self.MaxLen:
+ self.MaxLen = len(Symbol)
+ self.ItemList.append((Phase, Symbol, FilePath))
+ 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
+ #
+ def _GenerateExecutionOrderReport(self, File):
+ self._InvokeEotTool()
+ if len(self.ItemList) == 0:
+ return
+ FileWrite(File, gSectionStart)
+ FileWrite(File, "Execution Order Prediction")
+ FileWrite(File, "*P PEI phase")
+ FileWrite(File, "*D DXE phase")
+ FileWrite(File, "*E Module INF entry point name")
+ FileWrite(File, "*N Module notification function name")
+
+ FileWrite(File, "Type %-*s %s" % (self.MaxLen, "Symbol", "Module INF Path"))
+ FileWrite(File, gSectionSep)
+ for Item in self.ItemList:
+ FileWrite(File, "*%sE %-*s %s" % (Item[0], self.MaxLen, Item[1], Item[2]))
+
+ FileWrite(File, gSectionStart)
+
+ ##
+ # 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
+ #
+ def _GenerateFixedAddressReport(self, File, Guid, NotifyList):
+ self._ParseMapFile()
+ FixedAddressList = self.FixedMapDict.get(Guid)
+ if not FixedAddressList:
+ return
+
+ FileWrite(File, gSubSectionStart)
+ FileWrite(File, "Fixed Address Prediction")
+ FileWrite(File, "*I Image Loading Address")
+ FileWrite(File, "*E Entry Point Address")
+ FileWrite(File, "*N Notification Function Address")
+ FileWrite(File, "*F Flash Address")
+ FileWrite(File, "*M Memory Address")
+ FileWrite(File, "*S SMM RAM Offset")
+ FileWrite(File, "TOM Top of Memory")
+
+ FileWrite(File, "Type Address Name")
+ FileWrite(File, gSubSectionSep)
+ for Item in FixedAddressList:
+ Type = Item[0]
+ Value = Item[1]
+ Symbol = Item[2]
+ if Symbol == "*I":
+ Name = "(Image Base)"
+ elif Symbol == "*E":
+ Name = self._FfsEntryPoint.get(Guid, ["", "_ModuleEntryPoint"])[1]
+ elif Symbol in NotifyList:
+ Name = Symbol
+ Symbol = "*N"
+ else:
+ continue
+
+ if "Flash" in Type:
+ Symbol += "F"
+ elif "Memory" in Type:
+ Symbol += "M"
+ else:
+ Symbol += "S"
+
+ if Value[0] == "-":
+ Value = "TOM" + Value
+
+ FileWrite(File, "%s %-16s %s" % (Symbol, Value, Name))
+
+ ##
+ # 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.
+ #
+ def GenerateReport(self, File, Guid):
+ if Guid:
+ self._GenerateFixedAddressReport(File, Guid.upper(), [])
+ else:
+ self._GenerateExecutionOrderReport(File)
+
+##
+# 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
+#
+class FdRegionReport(object):
+ ##
+ # 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
+ #
+ def _DiscoverNestedFvList(self, FvName, Wa):
+ FvDictKey=FvName.upper()
+ if FvDictKey in Wa.FdfProfile.FvDict:
+ for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
+ for Section in Ffs.SectionList:
+ try:
+ for FvSection in Section.SectionList:
+ if FvSection.FvName in self.FvList:
+ continue
+ self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName
+ self.FvList.append(FvSection.FvName)
+ self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0)
+ self._DiscoverNestedFvList(FvSection.FvName, Wa)
+ 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
+ #
+ def __init__(self, FdRegion, Wa):
+ self.Type = FdRegion.RegionType
+ self.BaseAddress = FdRegion.Offset
+ self.Size = FdRegion.Size
+ self.FvList = []
+ self.FvInfo = {}
+ self._GuidsDb = {}
+ self._FvDir = Wa.FvDir
+ self._WorkspaceDir = Wa.WorkspaceDir
+
+ #
+ # If the input FdRegion is not a firmware volume,
+ # we are done.
+ #
+ if self.Type != BINARY_FILE_TYPE_FV:
+ return
+
+ #
+ # Find all nested FVs in the FdRegion
+ #
+ for FvName in FdRegion.RegionDataList:
+ if FvName in self.FvList:
+ continue
+ self.FvList.append(FvName)
+ self.FvInfo[FvName] = ("Fd Region", self.BaseAddress, self.Size)
+ self._DiscoverNestedFvList(FvName, Wa)
+
+ PlatformPcds = {}
+ #
+ # Collect PCDs declared in DEC files.
+ #
+ for Pa in Wa.AutoGenObjectList:
+ for Package in Pa.PackageList:
+ for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:
+ DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue
+ PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue
+ #
+ # Collect PCDs defined in DSC file
+ #
+ for Pa in Wa.AutoGenObjectList:
+ for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:
+ DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue
+ PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
+
+ #
+ # Add PEI and DXE a priori files GUIDs defined in PI specification.
+ #
+ self._GuidsDb[PEI_APRIORI_GUID] = "PEI Apriori"
+ self._GuidsDb[DXE_APRIORI_GUID] = "DXE Apriori"
+ #
+ # Add ACPI table storage file
+ #
+ self._GuidsDb["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
+
+ for Pa in Wa.AutoGenObjectList:
+ for ModuleKey in Pa.Platform.Modules:
+ M = Pa.Platform.Modules[ModuleKey].M
+ InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File)
+ self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath)
+
+ #
+ # Collect the GUID map in the FV firmware volume
+ #
+ for FvName in self.FvList:
+ FvDictKey=FvName.upper()
+ if FvDictKey in Wa.FdfProfile.FvDict:
+ for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
+ try:
+ #
+ # collect GUID map for binary EFI file in FDF file.
+ #
+ Guid = Ffs.NameGuid.upper()
+ Match = gPcdGuidPattern.match(Ffs.NameGuid)
+ if Match:
+ PcdTokenspace = Match.group(1)
+ PcdToken = Match.group(2)
+ if (PcdToken, PcdTokenspace) in PlatformPcds:
+ GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)]
+ Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()
+ for Section in Ffs.SectionList:
+ try:
+ ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName)
+ self._GuidsDb[Guid] = ModuleSectFile
+ 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
+ #
+ def _GenerateReport(self, File, Title, Type, BaseAddress, Size=0, FvName=None):
+ FileWrite(File, gSubSectionStart)
+ FileWrite(File, Title)
+ FileWrite(File, "Type: %s" % Type)
+ FileWrite(File, "Base Address: 0x%X" % BaseAddress)
+
+ if self.Type == BINARY_FILE_TYPE_FV:
+ FvTotalSize = 0
+ FvTakenSize = 0
+ FvFreeSize = 0
+ if FvName.upper().endswith('.FV'):
+ FileExt = FvName + ".txt"
+ else:
+ FileExt = FvName + ".Fv.txt"
+
+ if not os.path.isfile(FileExt):
+ FvReportFileName = mws.join(self._WorkspaceDir, FileExt)
+ if not os.path.isfile(FvReportFileName):
+ FvReportFileName = os.path.join(self._FvDir, FileExt)
+ try:
+ #
+ # Collect size info in the firmware volume.
+ #
+ FvReport = open(FvReportFileName).read()
+ Match = gFvTotalSizePattern.search(FvReport)
+ if Match:
+ FvTotalSize = int(Match.group(1), 16)
+ Match = gFvTakenSizePattern.search(FvReport)
+ if Match:
+ FvTakenSize = int(Match.group(1), 16)
+ FvFreeSize = FvTotalSize - FvTakenSize
+ #
+ # Write size information to the report file.
+ #
+ FileWrite(File, "Size: 0x%X (%.0fK)" % (FvTotalSize, FvTotalSize / 1024.0))
+ FileWrite(File, "Fv Name: %s (%.1f%% Full)" % (FvName, FvTakenSize * 100.0 / FvTotalSize))
+ FileWrite(File, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize, FvTakenSize / 1024.0))
+ FileWrite(File, "Free Size: 0x%X (%.0fK)" % (FvFreeSize, FvFreeSize / 1024.0))
+ FileWrite(File, "Offset Module")
+ FileWrite(File, gSubSectionSep)
+ #
+ # Write module offset and module identification to the report file.
+ #
+ OffsetInfo = {}
+ for Match in gOffsetGuidPattern.finditer(FvReport):
+ Guid = Match.group(2).upper()
+ OffsetInfo[Match.group(1)] = self._GuidsDb.get(Guid, Guid)
+ OffsetList = sorted(OffsetInfo.keys())
+ for Offset in OffsetList:
+ FileWrite (File, "%s %s" % (Offset, OffsetInfo[Offset]))
+ except IOError:
+ EdkLogger.warn(None, "Fail to read report file", FvReportFileName)
+ else:
+ FileWrite(File, "Size: 0x%X (%.0fK)" % (Size, Size / 1024.0))
+ FileWrite(File, gSubSectionEnd)
+
+ ##
+ # 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
+ #
+ def GenerateReport(self, File):
+ if (len(self.FvList) > 0):
+ for FvItem in self.FvList:
+ Info = self.FvInfo[FvItem]
+ self._GenerateReport(File, Info[0], TAB_FV_DIRECTORY, Info[1], Info[2], FvItem)
+ else:
+ self._GenerateReport(File, "FD Region", self.Type, self.BaseAddress, self.Size)
+
+##
+# Reports FD information
+#
+# This class reports the FD section in the build report file.
+# It collects flash device information for a platform.
+#
+class FdReport(object):
+ ##
+ # 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
+ #
+ def __init__(self, Fd, Wa):
+ self.FdName = Fd.FdUiName
+ self.BaseAddress = Fd.BaseAddress
+ self.Size = Fd.Size
+ self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList]
+ self.FvPath = os.path.join(Wa.BuildDir, TAB_FV_DIRECTORY)
+ self.VPDBaseAddress = 0
+ self.VPDSize = 0
+ for index, FdRegion in enumerate(Fd.RegionList):
+ if str(FdRegion.RegionType) == 'FILE' and Wa.Platform.VpdToolGuid in str(FdRegion.RegionDataList):
+ self.VPDBaseAddress = self.FdRegionList[index].BaseAddress
+ self.VPDSize = self.FdRegionList[index].Size
+ break
+
+ ##
+ # 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
+ #
+ def GenerateReport(self, File):
+ FileWrite(File, gSectionStart)
+ FileWrite(File, "Firmware Device (FD)")
+ FileWrite(File, "FD Name: %s" % self.FdName)
+ FileWrite(File, "Base Address: %s" % self.BaseAddress)
+ FileWrite(File, "Size: 0x%X (%.0fK)" % (self.Size, self.Size / 1024.0))
+ if len(self.FdRegionList) > 0:
+ FileWrite(File, gSectionSep)
+ for FdRegionItem in self.FdRegionList:
+ FdRegionItem.GenerateReport(File)
+
+ if VPDPcdList:
+ VPDPcdList.sort(key=lambda x: int(x[2], 0))
+ FileWrite(File, gSubSectionStart)
+ FileWrite(File, "FD VPD Region")
+ FileWrite(File, "Base Address: 0x%X" % self.VPDBaseAddress)
+ FileWrite(File, "Size: 0x%X (%.0fK)" % (self.VPDSize, self.VPDSize / 1024.0))
+ FileWrite(File, gSubSectionSep)
+ for item in VPDPcdList:
+ # Add BaseAddress for offset
+ Offset = '0x%08X' % (int(item[2], 16) + self.VPDBaseAddress)
+ IsByteArray, ArrayList = ByteArrayForamt(item[-1])
+ Skuinfo = item[1]
+ if len(GlobalData.gSkuids) == 1 :
+ Skuinfo = GlobalData.gSkuids[0]
+ if IsByteArray:
+ FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], '{'))
+ for Array in ArrayList:
+ FileWrite(File, Array)
+ else:
+ FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], item[-1]))
+ FileWrite(File, gSubSectionEnd)
+ FileWrite(File, gSectionEnd)
+
+
+
+##
+# Reports platform information
+#
+# This class reports the whole platform information
+#
+class PlatformReport(object):
+ ##
+ # 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
+ #
+ def __init__(self, Wa, MaList, ReportType):
+ self._WorkspaceDir = Wa.WorkspaceDir
+ self.PlatformName = Wa.Name
+ self.PlatformDscPath = Wa.Platform
+ self.Architectures = " ".join(Wa.ArchList)
+ self.ToolChain = Wa.ToolChain
+ self.Target = Wa.BuildTarget
+ self.OutputPath = os.path.join(Wa.WorkspaceDir, Wa.OutputDir)
+ self.BuildEnvironment = platform.platform()
+
+ self.PcdReport = None
+ if "PCD" in ReportType:
+ self.PcdReport = PcdReport(Wa)
+
+ self.FdReportList = []
+ if "FLASH" in ReportType and Wa.FdfProfile and MaList is None:
+ for Fd in Wa.FdfProfile.FdDict:
+ self.FdReportList.append(FdReport(Wa.FdfProfile.FdDict[Fd], Wa))
+
+ self.PredictionReport = None
+ if "FIXED_ADDRESS" in ReportType or "EXECUTION_ORDER" in ReportType:
+ self.PredictionReport = PredictionReport(Wa)
+
+ self.DepexParser = None
+ if "DEPEX" in ReportType:
+ self.DepexParser = DepexParser(Wa)
+
+ self.ModuleReportList = []
+ if MaList is not None:
+ self._IsModuleBuild = True
+ for Ma in MaList:
+ self.ModuleReportList.append(ModuleReport(Ma, ReportType))
+ else:
+ self._IsModuleBuild = False
+ for Pa in Wa.AutoGenObjectList:
+ ModuleAutoGenList = []
+ for ModuleKey in Pa.Platform.Modules:
+ ModuleAutoGenList.append(Pa.Platform.Modules[ModuleKey].M)
+ if GlobalData.gFdfParser is not None:
+ if Pa.Arch in GlobalData.gFdfParser.Profile.InfDict:
+ INFList = GlobalData.gFdfParser.Profile.InfDict[Pa.Arch]
+ for InfName in INFList:
+ InfClass = PathClass(NormPath(InfName), Wa.WorkspaceDir, Pa.Arch)
+ Ma = ModuleAutoGen(Wa, InfClass, Pa.BuildTarget, Pa.ToolChain, Pa.Arch, Wa.MetaFile, Pa.DataPipe)
+ if Ma is None:
+ continue
+ if Ma not in ModuleAutoGenList:
+ ModuleAutoGenList.append(Ma)
+ for MGen in ModuleAutoGenList:
+ self.ModuleReportList.append(ModuleReport(MGen, ReportType))
+
+
+
+ ##
+ # 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 AutoGenTime The total time of AutoGen Phase
+ # @param MakeTime The total time of Make Phase
+ # @param GenFdsTime The total time of GenFds Phase
+ # @param ReportType The kind of report items in the final report file
+ #
+ def GenerateReport(self, File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, ReportType):
+ FileWrite(File, "Platform Summary")
+ FileWrite(File, "Platform Name: %s" % self.PlatformName)
+ FileWrite(File, "Platform DSC Path: %s" % self.PlatformDscPath)
+ FileWrite(File, "Architectures: %s" % self.Architectures)
+ FileWrite(File, "Tool Chain: %s" % self.ToolChain)
+ FileWrite(File, "Target: %s" % self.Target)
+ if GlobalData.gSkuids:
+ FileWrite(File, "SKUID: %s" % " ".join(GlobalData.gSkuids))
+ if GlobalData.gDefaultStores:
+ FileWrite(File, "DefaultStore: %s" % " ".join(GlobalData.gDefaultStores))
+ FileWrite(File, "Output Path: %s" % self.OutputPath)
+ FileWrite(File, "Build Environment: %s" % self.BuildEnvironment)
+ FileWrite(File, "Build Duration: %s" % BuildDuration)
+ if AutoGenTime:
+ FileWrite(File, "AutoGen Duration: %s" % AutoGenTime)
+ if MakeTime:
+ FileWrite(File, "Make Duration: %s" % MakeTime)
+ if GenFdsTime:
+ FileWrite(File, "GenFds Duration: %s" % GenFdsTime)
+ FileWrite(File, "Report Content: %s" % ", ".join(ReportType))
+
+ if GlobalData.MixedPcd:
+ FileWrite(File, gSectionStart)
+ FileWrite(File, "The following PCDs use different access methods:")
+ FileWrite(File, gSectionSep)
+ for PcdItem in GlobalData.MixedPcd:
+ FileWrite(File, "%s.%s" % (str(PcdItem[1]), str(PcdItem[0])))
+ FileWrite(File, gSectionEnd)
+
+ if not self._IsModuleBuild:
+ if "PCD" in ReportType:
+ self.PcdReport.GenerateReport(File, None)
+
+ if "FLASH" in ReportType:
+ for FdReportListItem in self.FdReportList:
+ FdReportListItem.GenerateReport(File)
+
+ for ModuleReportItem in self.ModuleReportList:
+ ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, self.DepexParser, ReportType)
+
+ if not self._IsModuleBuild:
+ if "EXECUTION_ORDER" in ReportType:
+ self.PredictionReport.GenerateReport(File, None)
+
+## BuildReport class
+#
+# This base class contain the routines to collect data and then
+# applies certain format to the output report
+#
+class BuildReport(object):
+ ##
+ # 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
+ #
+ def __init__(self, ReportFile, ReportType):
+ self.ReportFile = ReportFile
+ if ReportFile:
+ self.ReportList = []
+ self.ReportType = []
+ if ReportType:
+ for ReportTypeItem in ReportType:
+ if ReportTypeItem not in self.ReportType:
+ self.ReportType.append(ReportTypeItem)
+ else:
+ self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
+ ##
+ # 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
+ #
+ def AddPlatformReport(self, Wa, MaList=None):
+ if self.ReportFile:
+ self.ReportList.append((Wa, MaList))
+
+ ##
+ # 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
+ # @param AutoGenTime The total time of AutoGen phase
+ # @param MakeTime The total time of Make phase
+ # @param GenFdsTime The total time of GenFds phase
+ #
+ def GenerateReport(self, BuildDuration, AutoGenTime, MakeTime, GenFdsTime):
+ if self.ReportFile:
+ try:
+
+ if "COMPILE_INFO" in self.ReportType:
+ self.GenerateCompileInfo()
+
+ File = []
+ for (Wa, MaList) in self.ReportList:
+ PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, self.ReportType)
+ Content = FileLinesSplit(''.join(File), gLineMaxLength)
+ SaveFileOnChange(self.ReportFile, Content, False)
+ EdkLogger.quiet("Build report can be found at %s" % os.path.abspath(self.ReportFile))
+ except IOError:
+ EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)
+ 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()))
+
+
+ ##
+ # Generates compile data files to be used by external tools.
+ # Compile information will be generated in <Build>/<BuildTarget>/<ToolChain>/CompileInfo
+ # Files generated: compile_commands.json, cscope.files, modules_report.json
+ #
+ # @param self The object pointer
+ #
+ def GenerateCompileInfo(self):
+ try:
+ # Lists for the output elements
+ compile_commands = []
+ used_files = set()
+ module_report = []
+
+ for (Wa, MaList) in self.ReportList:
+ # Obtain list of all processed Workspace files
+ for file_path in Wa._GetMetaFiles(Wa.BuildTarget, Wa.ToolChain):
+ used_files.add(file_path)
+
+ for autoGen in Wa.AutoGenObjectList:
+
+ # Loop through all modules
+ for module in (autoGen.LibraryAutoGenList + autoGen.ModuleAutoGenList):
+
+ used_files.add(module.MetaFile.Path)
+
+ # Main elements of module report
+ module_report_data = {}
+ module_report_data["Name"] = module.Name
+ module_report_data["Arch"] = module.Arch
+ module_report_data["Path"] = module.MetaFile.Path
+ module_report_data["Guid"] = module.Guid
+ module_report_data["BuildType"] = module.BuildType
+ module_report_data["IsLibrary"] = module.IsLibrary
+ module_report_data["SourceDir"] = module.SourceDir
+ module_report_data["Files"] = []
+ module_report_data["LibraryClass"] = module.Module.LibraryClass
+ module_report_data["ModuleEntryPointList"] = module.Module.ModuleEntryPointList
+ module_report_data["ConstructorList"] = module.Module.ConstructorList
+ module_report_data["DestructorList"] = module.Module.DestructorList
+
+ # Files used by module
+ for data_file in module.SourceFileList:
+ module_report_data["Files"].append({"Name": data_file.Name, "Path": data_file.Path})
+
+ # Libraries used by module
+ module_report_data["Libraries"] = []
+ for data_library in module.LibraryAutoGenList:
+ module_report_data["Libraries"].append({"Path": data_library.MetaFile.Path})
+
+ # Packages used by module
+ module_report_data["Packages"] = []
+ for data_package in module.PackageList:
+ module_report_data["Packages"].append({"Path": data_package.MetaFile.Path, "Includes": []})
+ # Includes path used in package
+ for data_package_include in data_package.Includes:
+ module_report_data["Packages"][-1]["Includes"].append(data_package_include.Path)
+
+ # PPI's in module
+ module_report_data["PPI"] = []
+ for data_ppi in module.PpiList.keys():
+ module_report_data["PPI"].append({"Name": data_ppi, "Guid": module.PpiList[data_ppi]})
+
+ # Protocol's in module
+ module_report_data["Protocol"] = []
+ for data_protocol in module.ProtocolList.keys():
+ module_report_data["Protocol"].append({"Name": data_protocol, "Guid": module.ProtocolList[data_protocol]})
+
+ # PCD's in module
+ module_report_data["Pcd"] = []
+ for data_pcd in module.LibraryPcdList:
+ module_report_data["Pcd"].append({"Space": data_pcd.TokenSpaceGuidCName,
+ "Name": data_pcd.TokenCName,
+ "Value": data_pcd.TokenValue,
+ "Guid": data_pcd.TokenSpaceGuidValue,
+ "DatumType": data_pcd.DatumType,
+ "Type": data_pcd.Type,
+ "DefaultValue": data_pcd.DefaultValue})
+ # Add module to report
+ module_report.append(module_report_data)
+
+ # Include file dependencies to used files
+ includes_autogen = IncludesAutoGen(module.MakeFileDir, module)
+ for dep in includes_autogen.DepsCollection:
+ used_files.add(dep)
+
+ inc_flag = "-I" # Default include flag
+ if module.BuildRuleFamily == TAB_COMPILER_MSFT:
+ inc_flag = "/I"
+
+ for source in module.SourceFileList:
+ used_files.add(source.Path)
+ compile_command = {}
+ if source.Ext in [".c", ".cc", ".cpp"]:
+ #
+ # Generate compile command for each c file
+ #
+ compile_command["file"] = source.Path
+ compile_command["directory"] = source.Dir
+ build_command = module.BuildRules[source.Ext].CommandList[0]
+ build_command_variables = re.findall(r"\$\((.*?)\)", build_command)
+ for var in build_command_variables:
+ var_tokens = var.split("_")
+ var_main = var_tokens[0]
+ if len(var_tokens) == 1:
+ var_value = module.BuildOption[var_main]["PATH"]
+ else:
+ var_value = module.BuildOption[var_main][var_tokens[1]]
+ build_command = build_command.replace(f"$({var})", var_value)
+ include_files = f" {inc_flag}".join(module.IncludePathList)
+ build_command = build_command.replace("${src}", include_files)
+ build_command = build_command.replace("${dst}", module.OutputDir)
+
+ # Remove un defined macros
+ compile_command["command"] = re.sub(r"\$\(.*?\)", "", build_command)
+ compile_commands.append(compile_command)
+
+ # Create output folder if doesn't exist
+ compile_info_folder = Path(Wa.BuildDir).joinpath("CompileInfo")
+ compile_info_folder.mkdir(exist_ok=True)
+
+ # Sort and save files
+ compile_commands.sort(key=lambda x: x["file"])
+ SaveFileOnChange(compile_info_folder.joinpath(f"compile_commands.json"),json.dumps(compile_commands, indent=2), False)
+
+ SaveFileOnChange(compile_info_folder.joinpath(f"cscope.files"), "\n".join(sorted(used_files)), False)
+
+ module_report.sort(key=lambda x: x["Path"])
+ SaveFileOnChange(compile_info_folder.joinpath(f"module_report.json"), json.dumps(module_report, indent=2), False)
+
+ except:
+ EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report compile information", 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