Signed-off-by: Liming Gao <liming.gao@intel.com> Reviewed-by: Liu Yingke <yingke.d.liu@intel.com> Reviewed-by: Yurui Zeng <yurui.zeng@intel.com> git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13353 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1571 lines
		
	
	
		
			66 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1571 lines
		
	
	
		
			66 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, Intel Corporation. All rights reserved.<BR>
 | 
						|
# This program and the accompanying materials
 | 
						|
# are licensed and made available under the terms and conditions of the BSD License
 | 
						|
# which accompanies this distribution.  The full text of the license may be found at
 | 
						|
# http://opensource.org/licenses/bsd-license.php
 | 
						|
#
 | 
						|
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
#
 | 
						|
 | 
						|
## Import Modules
 | 
						|
#
 | 
						|
import os
 | 
						|
import re
 | 
						|
import platform
 | 
						|
import textwrap
 | 
						|
import traceback
 | 
						|
import sys
 | 
						|
import time
 | 
						|
import struct
 | 
						|
from datetime import datetime
 | 
						|
from StringIO import StringIO
 | 
						|
from Common import EdkLogger
 | 
						|
from Common.Misc import SaveFileOnChange
 | 
						|
from Common.Misc import GuidStructureByteArrayToGuidString
 | 
						|
from Common.Misc import GuidStructureStringToGuidString
 | 
						|
from Common.InfClassObject import gComponentType2ModuleType
 | 
						|
from Common.BuildToolError import FILE_WRITE_FAILURE
 | 
						|
from Common.BuildToolError import CODE_ERROR
 | 
						|
from Common.DataType import TAB_LINE_BREAK
 | 
						|
from Common.DataType import TAB_DEPEX
 | 
						|
from Common.DataType import TAB_SLASH
 | 
						|
from Common.DataType import TAB_SPACE_SPLIT
 | 
						|
from Common.DataType import TAB_BRG_PCD
 | 
						|
from Common.DataType import TAB_BRG_LIBRARY
 | 
						|
from Common.DataType import TAB_BACK_SLASH
 | 
						|
 | 
						|
## 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*\(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 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 = {
 | 
						|
  'FixedAtBuild'     : ('FIXED',  'FixedAtBuild'),
 | 
						|
  'PatchableInModule': ('PATCH',  'PatchableInModule'),
 | 
						|
  'FeatureFlag'      : ('FLAG',   'FeatureFlag'),
 | 
						|
  'Dynamic'          : ('DYN',    'Dynamic'),
 | 
						|
  'DynamicHii'       : ('DYNHII', 'Dynamic'),
 | 
						|
  'DynamicVpd'       : ('DYNVPD', 'Dynamic'),
 | 
						|
  'DynamicEx'        : ('DEX',    'Dynamic'),
 | 
						|
  'DynamicExHii'     : ('DEXHII', 'Dynamic'),
 | 
						|
  'DynamicExVpd'     : ('DEXVPD', 'Dynamic'),
 | 
						|
  }
 | 
						|
 | 
						|
## The look up table to map module type to driver type
 | 
						|
gDriverTypeMap = {
 | 
						|
  'SEC'               : '0x3 (SECURITY_CORE)',
 | 
						|
  'PEI_CORE'          : '0x4 (PEI_CORE)',
 | 
						|
  'PEIM'              : '0x6 (PEIM)',
 | 
						|
  'DXE_CORE'          : '0x5 (DXE_CORE)',
 | 
						|
  'DXE_DRIVER'        : '0x7 (DRIVER)',
 | 
						|
  'DXE_SAL_DRIVER'    : '0x7 (DRIVER)',
 | 
						|
  'DXE_SMM_DRIVER'    : '0x7 (DRIVER)',
 | 
						|
  'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',
 | 
						|
  'UEFI_DRIVER'       : '0x7 (DRIVER)',
 | 
						|
  'UEFI_APPLICATION'  : '0x9 (APPLICATION)',
 | 
						|
  'SMM_CORE'          : '0xD (SMM_CORE)',
 | 
						|
  'SMM_DRIVER'        : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
 | 
						|
  }
 | 
						|
 | 
						|
## The look up table of the supported opcode in the dependency expression binaries
 | 
						|
gOpCodeList = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
 | 
						|
 | 
						|
##
 | 
						|
# 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.write(String + "\r\n")
 | 
						|
 | 
						|
##
 | 
						|
# 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 "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
 | 
						|
    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
 | 
						|
    
 | 
						|
    ##
 | 
						|
    # 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("LHHBBBBBBBB", 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 = []
 | 
						|
        if int(str(M.AutoGenVersion), 0) >= 0x00010005:
 | 
						|
            self._EdkIIModule = True
 | 
						|
        else:
 | 
						|
            self._EdkIIModule = False
 | 
						|
 | 
						|
        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]
 | 
						|
            self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList))
 | 
						|
 | 
						|
    ##
 | 
						|
    # Generate report for module library information
 | 
						|
    #
 | 
						|
    # This function generates report for the module library.
 | 
						|
    # If the module is EDKII style one, the additional library class, library
 | 
						|
    # constructor/destructor and dependency expression may also be reported.
 | 
						|
    #
 | 
						|
    # @param self            The object pointer
 | 
						|
    # @param File            The file object for report
 | 
						|
    #
 | 
						|
    def GenerateReport(self, File):
 | 
						|
        FileWrite(File, gSubSectionStart)
 | 
						|
        FileWrite(File, TAB_BRG_LIBRARY)
 | 
						|
        if len(self.LibraryList) > 0:
 | 
						|
            FileWrite(File, gSubSectionSep)
 | 
						|
            for LibraryItem in self.LibraryList:
 | 
						|
                LibInfPath = LibraryItem[0]
 | 
						|
                FileWrite(File, LibInfPath)
 | 
						|
 | 
						|
                #
 | 
						|
                # Report library class, library constructor and destructor for
 | 
						|
                # EDKII style module.
 | 
						|
                #
 | 
						|
                if self._EdkIIModule:
 | 
						|
                    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 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 = gComponentType2ModuleType.get(M.ComponentType, "")
 | 
						|
 | 
						|
        if ModuleType in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "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.DepexExpressionList.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:
 | 
						|
            FileWrite(File, gSubSectionStart)
 | 
						|
            FileWrite(File, TAB_DEPEX)
 | 
						|
            FileWrite(File, gSubSectionEnd)
 | 
						|
            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, "%s" % 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, "%s" % 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.FileGuid = M.Guid
 | 
						|
        self.Size = 0
 | 
						|
        self.BuildTimeStamp = None
 | 
						|
        self.DriverType = ""
 | 
						|
        if not M.IsLibrary:
 | 
						|
            ModuleType = M.ModuleType
 | 
						|
            if not ModuleType:
 | 
						|
                ModuleType = gComponentType2ModuleType.get(M.ComponentType, "")
 | 
						|
            #
 | 
						|
            # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
 | 
						|
            #
 | 
						|
            if ModuleType == "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._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, "DEBUG", 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.fromtimestamp(int(Match.group(1)))
 | 
						|
            except IOError:
 | 
						|
                EdkLogger.warn(None, "Fail to read report file", FwReportFileName)
 | 
						|
 | 
						|
        FileWrite(File, "Module Summary")
 | 
						|
        FileWrite(File, "Module Name:          %s" % self.ModuleName)
 | 
						|
        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.BuildTimeStamp:
 | 
						|
            FileWrite(File, "Build Time Stamp:     %s" % self.BuildTimeStamp)
 | 
						|
        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)
 | 
						|
 | 
						|
        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)
 | 
						|
 | 
						|
##
 | 
						|
# 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.MaxLen = 0
 | 
						|
        if Wa.FdfProfile:
 | 
						|
            self.FdfPcdSet = Wa.FdfProfile.PcdDict
 | 
						|
        else:
 | 
						|
            self.FdfPcdSet = {}
 | 
						|
 | 
						|
        self.ModulePcdOverride = {}
 | 
						|
        for Pa in Wa.AutoGenObjectList:
 | 
						|
            #
 | 
						|
            # 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)
 | 
						|
 | 
						|
            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 = {}
 | 
						|
        for Pa in Wa.AutoGenObjectList:
 | 
						|
            for Package in Pa.PackageList:
 | 
						|
                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 Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList:
 | 
						|
            for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:
 | 
						|
                DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue
 | 
						|
                if DscDefaultValue:
 | 
						|
                    self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
 | 
						|
 | 
						|
    ##
 | 
						|
    # Generate report for PCD information
 | 
						|
    #
 | 
						|
    # This function generates report for separate module expression
 | 
						|
    # in a platform build.
 | 
						|
    #
 | 
						|
    # @param self            The object pointer
 | 
						|
    # @param File            The file object for report
 | 
						|
    # @param ModulePcdSet    Set of all PCDs referenced by module or None for
 | 
						|
    #                        platform PCD report
 | 
						|
    # @param DscOverridePcds Module DSC override PCDs set
 | 
						|
    #
 | 
						|
    def GenerateReport(self, File, ModulePcdSet):
 | 
						|
        if ModulePcdSet == None:
 | 
						|
            #
 | 
						|
            # For platform global PCD section
 | 
						|
            #
 | 
						|
            FileWrite(File, gSectionStart)
 | 
						|
            FileWrite(File, "Platform Configuration Database Report")
 | 
						|
            FileWrite(File, "  *P  - Platform scoped PCD override in DSC file")
 | 
						|
            FileWrite(File, "  *F  - Platform scoped PCD override in FDF file")
 | 
						|
            FileWrite(File, "  *M  - Module scoped PCD override")
 | 
						|
            FileWrite(File, gSectionSep)
 | 
						|
        else:
 | 
						|
            #
 | 
						|
            # For module PCD sub-section
 | 
						|
            #
 | 
						|
            FileWrite(File, gSubSectionStart)
 | 
						|
            FileWrite(File, TAB_BRG_PCD)
 | 
						|
            FileWrite(File, gSubSectionSep)
 | 
						|
 | 
						|
        for Key in self.AllPcds:
 | 
						|
            #
 | 
						|
            # Group PCD by their token space GUID C Name
 | 
						|
            #
 | 
						|
            First = True
 | 
						|
            for Type in self.AllPcds[Key]:
 | 
						|
                #
 | 
						|
                # Group PCD by their usage type
 | 
						|
                #
 | 
						|
                TypeName, DecType = gPcdTypeMap.get(Type, ("", Type))
 | 
						|
                for Pcd in self.AllPcds[Key][Type]:
 | 
						|
                    #
 | 
						|
                    # 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))
 | 
						|
                    DscDefaultValue = self.FdfPcdSet.get((Pcd.TokenCName, Key), DscDefaultValue)
 | 
						|
                    InfDefaultValue = None
 | 
						|
                    
 | 
						|
                    PcdValue = DecDefaultValue
 | 
						|
                    if DscDefaultValue:
 | 
						|
                        PcdValue = DscDefaultValue
 | 
						|
                    if ModulePcdSet != None:
 | 
						|
                        if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type) not in ModulePcdSet:
 | 
						|
                            continue
 | 
						|
                        InfDefault, PcdValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]
 | 
						|
                        if InfDefault == "":
 | 
						|
                            InfDefault = None
 | 
						|
                    if First:
 | 
						|
                        if ModulePcdSet == None:
 | 
						|
                            FileWrite(File, "")
 | 
						|
                        FileWrite(File, Key)
 | 
						|
                        First = False
 | 
						|
 | 
						|
 | 
						|
                    if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
 | 
						|
                        PcdValueNumber = int(PcdValue.strip(), 0)
 | 
						|
                        if DecDefaultValue == None:
 | 
						|
                            DecMatch = True
 | 
						|
                        else:
 | 
						|
                            DecDefaultValueNumber = int(DecDefaultValue.strip(), 0)
 | 
						|
                            DecMatch = (DecDefaultValueNumber == PcdValueNumber)
 | 
						|
 | 
						|
                        if InfDefaultValue == None:
 | 
						|
                            InfMatch = True
 | 
						|
                        else:
 | 
						|
                            InfDefaultValueNumber = int(InfDefaultValue.strip(), 0)
 | 
						|
                            InfMatch = (InfDefaultValueNumber == PcdValueNumber)
 | 
						|
 | 
						|
                        if DscDefaultValue == None:
 | 
						|
                            DscMatch = True
 | 
						|
                        else:
 | 
						|
                            DscDefaultValueNumber = int(DscDefaultValue.strip(), 0)
 | 
						|
                            DscMatch = (DscDefaultValueNumber == PcdValueNumber)
 | 
						|
                    else:
 | 
						|
                        if DecDefaultValue == None:
 | 
						|
                            DecMatch = True
 | 
						|
                        else:
 | 
						|
                            DecMatch = (DecDefaultValue.strip() == PcdValue.strip())
 | 
						|
 | 
						|
                        if InfDefaultValue == None:
 | 
						|
                            InfMatch = True
 | 
						|
                        else:
 | 
						|
                            InfMatch = (InfDefaultValue.strip() == PcdValue.strip())
 | 
						|
 | 
						|
                        if DscDefaultValue == None:
 | 
						|
                            DscMatch = True
 | 
						|
                        else:
 | 
						|
                            DscMatch = (DscDefaultValue.strip() == PcdValue.strip())
 | 
						|
 | 
						|
                    #
 | 
						|
                    # Report PCD item according to their override relationship
 | 
						|
                    #
 | 
						|
                    if DecMatch and InfMatch:
 | 
						|
                        FileWrite(File, '    %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))
 | 
						|
                    else:
 | 
						|
                        if DscMatch:
 | 
						|
                            if (Pcd.TokenCName, Key) in self.FdfPcdSet:
 | 
						|
                                FileWrite(File, ' *F %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))
 | 
						|
                            else:
 | 
						|
                                FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))
 | 
						|
                        else:
 | 
						|
                            FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, Pcd.TokenCName, TypeName, '('+Pcd.DatumType+')', PcdValue.strip()))
 | 
						|
                    
 | 
						|
                    if TypeName in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):
 | 
						|
                        for SkuInfo in Pcd.SkuInfoList.values():
 | 
						|
                            if TypeName in ('DYNHII', 'DEXHII'):
 | 
						|
                                FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset))        
 | 
						|
                            else:
 | 
						|
                                FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset))
 | 
						|
                               
 | 
						|
                    if not DscMatch and DscDefaultValue != None:
 | 
						|
                        FileWrite(File, '    %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', DscDefaultValue.strip()))
 | 
						|
 | 
						|
                    if not InfMatch and InfDefaultValue != None:
 | 
						|
                        FileWrite(File, '    %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', InfDefaultValue.strip()))
 | 
						|
 | 
						|
                    if not DecMatch and DecDefaultValue != None:
 | 
						|
                        FileWrite(File, '    %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', DecDefaultValue.strip()))
 | 
						|
 | 
						|
                    if ModulePcdSet == None:
 | 
						|
                        ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {})
 | 
						|
                        for ModulePath in ModuleOverride:
 | 
						|
                            ModuleDefault = ModuleOverride[ModulePath]
 | 
						|
                            if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
 | 
						|
                                ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)
 | 
						|
                                Match = (ModulePcdDefaultValueNumber == PcdValueNumber)
 | 
						|
                            else:
 | 
						|
                                Match = (ModuleDefault.strip() == PcdValue.strip())
 | 
						|
                            if Match:
 | 
						|
                                continue
 | 
						|
                            FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, ModuleDefault.strip()))
 | 
						|
 | 
						|
        if ModulePcdSet == None:
 | 
						|
            FileWrite(File, gSectionEnd)
 | 
						|
        else:
 | 
						|
            FileWrite(File, gSubSectionEnd)
 | 
						|
 | 
						|
 | 
						|
 | 
						|
##
 | 
						|
# 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 == "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)
 | 
						|
                    if int(str(Module.AutoGenVersion), 0) >= 0x00010005:
 | 
						|
                        RealEntryPoint = "_ModuleEntryPoint"
 | 
						|
                    else:
 | 
						|
                        RealEntryPoint = EntryPoint
 | 
						|
                        if EntryPoint == "_ModuleEntryPoint":
 | 
						|
                            CCFlags = Module.BuildOption.get("CC", {}).get("FLAGS", "")
 | 
						|
                            Match = gGlueLibEntryPoint.search(CCFlags)
 | 
						|
                            if Match:
 | 
						|
                                EntryPoint = Match.group(1)
 | 
						|
 | 
						|
                    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 != "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 = open(SourceList, "w+")
 | 
						|
        for Item in self._SourceList:
 | 
						|
            FileWrite(TempFile, Item)
 | 
						|
        TempFile.close()
 | 
						|
        TempFile = open(GuidList, "w+")
 | 
						|
        for Key in self._GuidMap:
 | 
						|
            FileWrite(TempFile, "%s %s" % (Key, self._GuidMap[Key]))
 | 
						|
        TempFile.close()
 | 
						|
 | 
						|
        try:
 | 
						|
            from Eot.Eot 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):
 | 
						|
        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
 | 
						|
 | 
						|
        #
 | 
						|
        # If the input FdRegion is not a firmware volume,
 | 
						|
        # we are done.
 | 
						|
        #
 | 
						|
        if self.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 common section
 | 
						|
        #
 | 
						|
        for Platform in Wa.BuildDatabase.WorkspaceDb.PlatformList:
 | 
						|
            for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:
 | 
						|
                DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue
 | 
						|
                PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
 | 
						|
 | 
						|
        #
 | 
						|
        # Add PEI and DXE a priori files GUIDs defined in PI specification.
 | 
						|
        #
 | 
						|
        self._GuidsDb["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
 | 
						|
        self._GuidsDb["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "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 = os.path.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:
 | 
						|
            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 = os.path.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 == "FV":
 | 
						|
            FvTotalSize = 0
 | 
						|
            FvTakenSize = 0
 | 
						|
            FvFreeSize  = 0
 | 
						|
            FvReportFileName = os.path.join(self._FvDir, FvName + ".Fv.txt")
 | 
						|
            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 = OffsetInfo.keys()
 | 
						|
                OffsetList.sort()
 | 
						|
                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], "FV", 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]
 | 
						|
 | 
						|
    ##
 | 
						|
    # 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)
 | 
						|
 | 
						|
        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 == 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 != None:
 | 
						|
            self._IsModuleBuild = True
 | 
						|
            for Ma in MaList:
 | 
						|
                self.ModuleReportList.append(ModuleReport(Ma, ReportType))
 | 
						|
        else:
 | 
						|
            self._IsModuleBuild = False
 | 
						|
            for Pa in Wa.AutoGenObjectList:
 | 
						|
                for ModuleKey in Pa.Platform.Modules:
 | 
						|
                    self.ModuleReportList.append(ModuleReport(Pa.Platform.Modules[ModuleKey].M, 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 ReportType      The kind of report items in the final report file
 | 
						|
    #
 | 
						|
    def GenerateReport(self, File, BuildDuration, 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)
 | 
						|
        FileWrite(File, "Output Path:          %s" % self.OutputPath)
 | 
						|
        FileWrite(File, "Build Environment:    %s" % self.BuildEnvironment)
 | 
						|
        FileWrite(File, "Build Duration:       %s" % BuildDuration)
 | 
						|
        FileWrite(File, "Report Content:       %s" % ", ".join(ReportType))
 | 
						|
 | 
						|
        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", "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
 | 
						|
    #
 | 
						|
    def GenerateReport(self, BuildDuration):
 | 
						|
        if self.ReportFile:
 | 
						|
            try:
 | 
						|
                File = StringIO('')
 | 
						|
                for (Wa, MaList) in self.ReportList:
 | 
						|
                    PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, self.ReportType)
 | 
						|
                Content = FileLinesSplit(File.getvalue(), gLineMaxLength)
 | 
						|
                SaveFileOnChange(self.ReportFile, Content, True)
 | 
						|
                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()))
 | 
						|
            File.close()
 | 
						|
            
 | 
						|
# This acts like the main() function for the script, unless it is 'import'ed into another script.
 | 
						|
if __name__ == '__main__':
 | 
						|
    pass
 | 
						|
 |