Adding following fields to module_report.json: * LibraryClass * ModuleEntryPointList * ConstructorList * DestructorList Signed-off-by: Guillermo Antonio Palomino Sosa <guillermo.a.palomino.sosa@intel.com> Reviewed-by: Bob Feng <bob.c.feng@intel.com>
		
			
				
	
	
		
			2458 lines
		
	
	
		
			118 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			2458 lines
		
	
	
		
			118 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| ## @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
 |