mirror of
https://github.com/acidanthera/audk.git
synced 2025-04-08 17:05:09 +02:00
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=1752 This patch is to fix the code bug in StructurePcd overall value assignment logic. If a Pcd Array size is fixed but the size of actual value in Dsc or Dec is bigger than the Pcd array size, the tool will report error about such setting and stop build. The patch is tested minplatform, Ovmf, structure pcd regression test These tests are build pass. The patch also tested the following cases. Our cases focused on PcdArraySize. 1.flexiable PcdArraySize. 2.Fixed PcdArraySize, Pcd overall value exceeds the size of PcdArray. 3.Fixed PcdArraySize, Pcd overall value Not exceeds the size of PcdArray. Signed-off-by: Bob Feng <bob.c.feng@intel.com> Cc: Liming Gao <liming.gao@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com>
476 lines
22 KiB
Python
476 lines
22 KiB
Python
## @file
|
|
# This file is used to create a database used by build tool
|
|
#
|
|
# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
|
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
#
|
|
from Common.StringUtils import *
|
|
from Common.DataType import *
|
|
from Common.Misc import *
|
|
from types import *
|
|
from collections import OrderedDict
|
|
from CommonDataClass.DataClass import *
|
|
from Workspace.BuildClassObject import PackageBuildClassObject, StructurePcd, PcdClassObject
|
|
from Common.GlobalData import gGlobalDefines
|
|
from re import compile
|
|
|
|
## Platform build information from DEC file
|
|
#
|
|
# This class is used to retrieve information stored in database and convert them
|
|
# into PackageBuildClassObject form for easier use for AutoGen.
|
|
#
|
|
class DecBuildData(PackageBuildClassObject):
|
|
# dict used to convert PCD type in database to string used by build tool
|
|
_PCD_TYPE_STRING_ = {
|
|
MODEL_PCD_FIXED_AT_BUILD : TAB_PCDS_FIXED_AT_BUILD,
|
|
MODEL_PCD_PATCHABLE_IN_MODULE : TAB_PCDS_PATCHABLE_IN_MODULE,
|
|
MODEL_PCD_FEATURE_FLAG : TAB_PCDS_FEATURE_FLAG,
|
|
MODEL_PCD_DYNAMIC : TAB_PCDS_DYNAMIC,
|
|
MODEL_PCD_DYNAMIC_DEFAULT : TAB_PCDS_DYNAMIC,
|
|
MODEL_PCD_DYNAMIC_HII : TAB_PCDS_DYNAMIC_HII,
|
|
MODEL_PCD_DYNAMIC_VPD : TAB_PCDS_DYNAMIC_VPD,
|
|
MODEL_PCD_DYNAMIC_EX : TAB_PCDS_DYNAMIC_EX,
|
|
MODEL_PCD_DYNAMIC_EX_DEFAULT : TAB_PCDS_DYNAMIC_EX,
|
|
MODEL_PCD_DYNAMIC_EX_HII : TAB_PCDS_DYNAMIC_EX_HII,
|
|
MODEL_PCD_DYNAMIC_EX_VPD : TAB_PCDS_DYNAMIC_EX_VPD,
|
|
}
|
|
|
|
# dict used to convert part of [Defines] to members of DecBuildData directly
|
|
_PROPERTY_ = {
|
|
#
|
|
# Required Fields
|
|
#
|
|
TAB_DEC_DEFINES_PACKAGE_NAME : "_PackageName",
|
|
TAB_DEC_DEFINES_PACKAGE_GUID : "_Guid",
|
|
TAB_DEC_DEFINES_PACKAGE_VERSION : "_Version",
|
|
TAB_DEC_DEFINES_PKG_UNI_FILE : "_PkgUniFile",
|
|
}
|
|
|
|
|
|
## Constructor of DecBuildData
|
|
#
|
|
# Initialize object of DecBuildData
|
|
#
|
|
# @param FilePath The path of package description file
|
|
# @param RawData The raw data of DEC file
|
|
# @param BuildDataBase Database used to retrieve module information
|
|
# @param Arch The target architecture
|
|
# @param Platform (not used for DecBuildData)
|
|
# @param Macros Macros used for replacement in DSC file
|
|
#
|
|
def __init__(self, File, RawData, BuildDataBase, Arch=TAB_ARCH_COMMON, Target=None, Toolchain=None):
|
|
self.MetaFile = File
|
|
self._PackageDir = File.Dir
|
|
self._RawData = RawData
|
|
self._Bdb = BuildDataBase
|
|
self._Arch = Arch
|
|
self._Target = Target
|
|
self._Toolchain = Toolchain
|
|
self._Clear()
|
|
|
|
## XXX[key] = value
|
|
def __setitem__(self, key, value):
|
|
self.__dict__[self._PROPERTY_[key]] = value
|
|
|
|
## value = XXX[key]
|
|
def __getitem__(self, key):
|
|
return self.__dict__[self._PROPERTY_[key]]
|
|
|
|
## "in" test support
|
|
def __contains__(self, key):
|
|
return key in self._PROPERTY_
|
|
|
|
## Set all internal used members of DecBuildData to None
|
|
def _Clear(self):
|
|
self._Header = None
|
|
self._PackageName = None
|
|
self._Guid = None
|
|
self._Version = None
|
|
self._PkgUniFile = None
|
|
self._Protocols = None
|
|
self._Ppis = None
|
|
self._Guids = None
|
|
self._Includes = None
|
|
self._CommonIncludes = None
|
|
self._LibraryClasses = None
|
|
self._Pcds = None
|
|
self._MacroDict = None
|
|
self._PrivateProtocols = None
|
|
self._PrivatePpis = None
|
|
self._PrivateGuids = None
|
|
self._PrivateIncludes = None
|
|
|
|
## Get current effective macros
|
|
@property
|
|
def _Macros(self):
|
|
if self._MacroDict is None:
|
|
self._MacroDict = dict(gGlobalDefines)
|
|
return self._MacroDict
|
|
|
|
## Get architecture
|
|
@property
|
|
def Arch(self):
|
|
return self._Arch
|
|
|
|
## Retrieve all information in [Defines] section
|
|
#
|
|
# (Retrieving all [Defines] information in one-shot is just to save time.)
|
|
#
|
|
def _GetHeaderInfo(self):
|
|
RecordList = self._RawData[MODEL_META_DATA_HEADER, self._Arch]
|
|
for Record in RecordList:
|
|
Name = Record[1]
|
|
if Name in self:
|
|
self[Name] = Record[2]
|
|
self._Header = 'DUMMY'
|
|
|
|
## Retrieve package name
|
|
@property
|
|
def PackageName(self):
|
|
if self._PackageName is None:
|
|
if self._Header is None:
|
|
self._GetHeaderInfo()
|
|
if self._PackageName is None:
|
|
EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "No PACKAGE_NAME", File=self.MetaFile)
|
|
return self._PackageName
|
|
|
|
## Retrieve file guid
|
|
@property
|
|
def PackageName(self):
|
|
if self._Guid is None:
|
|
if self._Header is None:
|
|
self._GetHeaderInfo()
|
|
if self._Guid is None:
|
|
EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "No PACKAGE_GUID", File=self.MetaFile)
|
|
return self._Guid
|
|
|
|
## Retrieve package version
|
|
@property
|
|
def Version(self):
|
|
if self._Version is None:
|
|
if self._Header is None:
|
|
self._GetHeaderInfo()
|
|
if self._Version is None:
|
|
self._Version = ''
|
|
return self._Version
|
|
|
|
## Retrieve protocol definitions (name/value pairs)
|
|
@property
|
|
def Protocols(self):
|
|
if self._Protocols is None:
|
|
#
|
|
# tdict is a special kind of dict, used for selecting correct
|
|
# protocol definition for given ARCH
|
|
#
|
|
ProtocolDict = tdict(True)
|
|
PrivateProtocolDict = tdict(True)
|
|
NameList = []
|
|
PrivateNameList = []
|
|
PublicNameList = []
|
|
# find out all protocol definitions for specific and 'common' arch
|
|
RecordList = self._RawData[MODEL_EFI_PROTOCOL, self._Arch]
|
|
for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:
|
|
if PrivateFlag == 'PRIVATE':
|
|
if Name not in PrivateNameList:
|
|
PrivateNameList.append(Name)
|
|
PrivateProtocolDict[Arch, Name] = Guid
|
|
if Name in PublicNameList:
|
|
EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)
|
|
else:
|
|
if Name not in PublicNameList:
|
|
PublicNameList.append(Name)
|
|
if Name in PrivateNameList:
|
|
EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)
|
|
if Name not in NameList:
|
|
NameList.append(Name)
|
|
ProtocolDict[Arch, Name] = Guid
|
|
# use OrderedDict to keep the order
|
|
self._Protocols = OrderedDict()
|
|
self._PrivateProtocols = OrderedDict()
|
|
for Name in NameList:
|
|
#
|
|
# limit the ARCH to self._Arch, if no self._Arch found, tdict
|
|
# will automatically turn to 'common' ARCH for trying
|
|
#
|
|
self._Protocols[Name] = ProtocolDict[self._Arch, Name]
|
|
for Name in PrivateNameList:
|
|
self._PrivateProtocols[Name] = PrivateProtocolDict[self._Arch, Name]
|
|
return self._Protocols
|
|
|
|
## Retrieve PPI definitions (name/value pairs)
|
|
@property
|
|
def Ppis(self):
|
|
if self._Ppis is None:
|
|
#
|
|
# tdict is a special kind of dict, used for selecting correct
|
|
# PPI definition for given ARCH
|
|
#
|
|
PpiDict = tdict(True)
|
|
PrivatePpiDict = tdict(True)
|
|
NameList = []
|
|
PrivateNameList = []
|
|
PublicNameList = []
|
|
# find out all PPI definitions for specific arch and 'common' arch
|
|
RecordList = self._RawData[MODEL_EFI_PPI, self._Arch]
|
|
for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:
|
|
if PrivateFlag == 'PRIVATE':
|
|
if Name not in PrivateNameList:
|
|
PrivateNameList.append(Name)
|
|
PrivatePpiDict[Arch, Name] = Guid
|
|
if Name in PublicNameList:
|
|
EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)
|
|
else:
|
|
if Name not in PublicNameList:
|
|
PublicNameList.append(Name)
|
|
if Name in PrivateNameList:
|
|
EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)
|
|
if Name not in NameList:
|
|
NameList.append(Name)
|
|
PpiDict[Arch, Name] = Guid
|
|
# use OrderedDict to keep the order
|
|
self._Ppis = OrderedDict()
|
|
self._PrivatePpis = OrderedDict()
|
|
for Name in NameList:
|
|
#
|
|
# limit the ARCH to self._Arch, if no self._Arch found, tdict
|
|
# will automatically turn to 'common' ARCH for trying
|
|
#
|
|
self._Ppis[Name] = PpiDict[self._Arch, Name]
|
|
for Name in PrivateNameList:
|
|
self._PrivatePpis[Name] = PrivatePpiDict[self._Arch, Name]
|
|
return self._Ppis
|
|
|
|
## Retrieve GUID definitions (name/value pairs)
|
|
@property
|
|
def Guids(self):
|
|
if self._Guids is None:
|
|
#
|
|
# tdict is a special kind of dict, used for selecting correct
|
|
# GUID definition for given ARCH
|
|
#
|
|
GuidDict = tdict(True)
|
|
PrivateGuidDict = tdict(True)
|
|
NameList = []
|
|
PrivateNameList = []
|
|
PublicNameList = []
|
|
# find out all protocol definitions for specific and 'common' arch
|
|
RecordList = self._RawData[MODEL_EFI_GUID, self._Arch]
|
|
for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:
|
|
if PrivateFlag == 'PRIVATE':
|
|
if Name not in PrivateNameList:
|
|
PrivateNameList.append(Name)
|
|
PrivateGuidDict[Arch, Name] = Guid
|
|
if Name in PublicNameList:
|
|
EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)
|
|
else:
|
|
if Name not in PublicNameList:
|
|
PublicNameList.append(Name)
|
|
if Name in PrivateNameList:
|
|
EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)
|
|
if Name not in NameList:
|
|
NameList.append(Name)
|
|
GuidDict[Arch, Name] = Guid
|
|
# use OrderedDict to keep the order
|
|
self._Guids = OrderedDict()
|
|
self._PrivateGuids = OrderedDict()
|
|
for Name in NameList:
|
|
#
|
|
# limit the ARCH to self._Arch, if no self._Arch found, tdict
|
|
# will automatically turn to 'common' ARCH for trying
|
|
#
|
|
self._Guids[Name] = GuidDict[self._Arch, Name]
|
|
for Name in PrivateNameList:
|
|
self._PrivateGuids[Name] = PrivateGuidDict[self._Arch, Name]
|
|
return self._Guids
|
|
|
|
## Retrieve public include paths declared in this package
|
|
@property
|
|
def Includes(self):
|
|
if self._Includes is None or self._CommonIncludes is None:
|
|
self._CommonIncludes = []
|
|
self._Includes = []
|
|
self._PrivateIncludes = []
|
|
PublicInclues = []
|
|
RecordList = self._RawData[MODEL_EFI_INCLUDE, self._Arch]
|
|
Macros = self._Macros
|
|
for Record in RecordList:
|
|
File = PathClass(NormPath(Record[0], Macros), self._PackageDir, Arch=self._Arch)
|
|
LineNo = Record[-1]
|
|
# validate the path
|
|
ErrorCode, ErrorInfo = File.Validate()
|
|
if ErrorCode != 0:
|
|
EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo)
|
|
|
|
# avoid duplicate include path
|
|
if File not in self._Includes:
|
|
self._Includes.append(File)
|
|
if Record[4] == 'PRIVATE':
|
|
if File not in self._PrivateIncludes:
|
|
self._PrivateIncludes.append(File)
|
|
if File in PublicInclues:
|
|
EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % File, File=self.MetaFile, Line=LineNo)
|
|
else:
|
|
if File not in PublicInclues:
|
|
PublicInclues.append(File)
|
|
if File in self._PrivateIncludes:
|
|
EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % File, File=self.MetaFile, Line=LineNo)
|
|
if Record[3] == TAB_COMMON:
|
|
self._CommonIncludes.append(File)
|
|
return self._Includes
|
|
|
|
## Retrieve library class declarations (not used in build at present)
|
|
@property
|
|
def LibraryClasses(self):
|
|
if self._LibraryClasses is None:
|
|
#
|
|
# tdict is a special kind of dict, used for selecting correct
|
|
# library class declaration for given ARCH
|
|
#
|
|
LibraryClassDict = tdict(True)
|
|
LibraryClassSet = set()
|
|
RecordList = self._RawData[MODEL_EFI_LIBRARY_CLASS, self._Arch]
|
|
Macros = self._Macros
|
|
for LibraryClass, File, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:
|
|
File = PathClass(NormPath(File, Macros), self._PackageDir, Arch=self._Arch)
|
|
# check the file validation
|
|
ErrorCode, ErrorInfo = File.Validate()
|
|
if ErrorCode != 0:
|
|
EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo)
|
|
LibraryClassSet.add(LibraryClass)
|
|
LibraryClassDict[Arch, LibraryClass] = File
|
|
self._LibraryClasses = OrderedDict()
|
|
for LibraryClass in LibraryClassSet:
|
|
self._LibraryClasses[LibraryClass] = LibraryClassDict[self._Arch, LibraryClass]
|
|
return self._LibraryClasses
|
|
|
|
## Retrieve PCD declarations
|
|
@property
|
|
def Pcds(self):
|
|
if self._Pcds is None:
|
|
self._Pcds = OrderedDict()
|
|
self._Pcds.update(self._GetPcd(MODEL_PCD_FIXED_AT_BUILD))
|
|
self._Pcds.update(self._GetPcd(MODEL_PCD_PATCHABLE_IN_MODULE))
|
|
self._Pcds.update(self._GetPcd(MODEL_PCD_FEATURE_FLAG))
|
|
self._Pcds.update(self._GetPcd(MODEL_PCD_DYNAMIC))
|
|
self._Pcds.update(self._GetPcd(MODEL_PCD_DYNAMIC_EX))
|
|
return self._Pcds
|
|
|
|
def ParsePcdName(self,TokenCName):
|
|
TokenCName = TokenCName.strip()
|
|
if TokenCName.startswith("["):
|
|
if "." in TokenCName:
|
|
Demesionattr = TokenCName[:TokenCName.index(".")]
|
|
Fields = TokenCName[TokenCName.index(".")+1:]
|
|
else:
|
|
Demesionattr = TokenCName
|
|
Fields = ""
|
|
else:
|
|
Demesionattr = ""
|
|
Fields = TokenCName
|
|
|
|
return Demesionattr,Fields
|
|
|
|
def ProcessStructurePcd(self, StructurePcdRawDataSet):
|
|
s_pcd_set = OrderedDict()
|
|
for s_pcd, LineNo in StructurePcdRawDataSet:
|
|
if s_pcd.TokenSpaceGuidCName not in s_pcd_set:
|
|
s_pcd_set[s_pcd.TokenSpaceGuidCName] = []
|
|
s_pcd_set[s_pcd.TokenSpaceGuidCName].append((s_pcd, LineNo))
|
|
|
|
str_pcd_set = []
|
|
for pcdname in s_pcd_set:
|
|
dep_pkgs = []
|
|
struct_pcd = StructurePcd()
|
|
for item, LineNo in s_pcd_set[pcdname]:
|
|
if not item.TokenCName:
|
|
continue
|
|
if "<HeaderFiles>" in item.TokenCName:
|
|
struct_pcd.StructuredPcdIncludeFile.append(item.DefaultValue)
|
|
elif "<Packages>" in item.TokenCName:
|
|
dep_pkgs.append(item.DefaultValue)
|
|
elif item.DatumType == item.TokenCName:
|
|
struct_pcd.copy(item)
|
|
struct_pcd.TokenValue = struct_pcd.TokenValue.strip("{").strip()
|
|
struct_pcd.TokenSpaceGuidCName, struct_pcd.TokenCName = pcdname.split(".")
|
|
struct_pcd.PcdDefineLineNo = LineNo
|
|
struct_pcd.PkgPath = self.MetaFile.File
|
|
struct_pcd.SetDecDefaultValue(item.DefaultValue,self.MetaFile.File,LineNo)
|
|
else:
|
|
DemesionAttr, Fields = self.ParsePcdName(item.TokenCName)
|
|
struct_pcd.AddDefaultValue(Fields, item.DefaultValue, self.MetaFile.File, LineNo,DemesionAttr)
|
|
|
|
struct_pcd.PackageDecs = dep_pkgs
|
|
str_pcd_set.append(struct_pcd)
|
|
return str_pcd_set
|
|
|
|
## Retrieve PCD declarations for given type
|
|
def _GetPcd(self, Type):
|
|
Pcds = OrderedDict()
|
|
#
|
|
# tdict is a special kind of dict, used for selecting correct
|
|
# PCD declaration for given ARCH
|
|
#
|
|
PcdDict = tdict(True, 3)
|
|
# for summarizing PCD
|
|
PcdSet = []
|
|
# find out all PCDs of the 'type'
|
|
|
|
StrPcdSet = []
|
|
RecordList = self._RawData[Type, self._Arch]
|
|
for TokenSpaceGuid, PcdCName, Setting, Arch, PrivateFlag, Dummy1, Dummy2 in RecordList:
|
|
PcdDict[Arch, PcdCName, TokenSpaceGuid] = (Setting, Dummy2)
|
|
if not (PcdCName, TokenSpaceGuid) in PcdSet:
|
|
PcdSet.append((PcdCName, TokenSpaceGuid))
|
|
|
|
DefinitionPosition = {}
|
|
for PcdCName, TokenSpaceGuid in PcdSet:
|
|
#
|
|
# limit the ARCH to self._Arch, if no self._Arch found, tdict
|
|
# will automatically turn to 'common' ARCH and try again
|
|
#
|
|
Setting, LineNo = PcdDict[self._Arch, PcdCName, TokenSpaceGuid]
|
|
if Setting is None:
|
|
continue
|
|
|
|
DefaultValue, DatumType, TokenNumber = AnalyzePcdData(Setting)
|
|
validateranges, validlists, expressions = self._RawData.GetValidExpression(TokenSpaceGuid, PcdCName)
|
|
PcdObj = PcdClassObject(
|
|
PcdCName,
|
|
TokenSpaceGuid,
|
|
self._PCD_TYPE_STRING_[Type],
|
|
DatumType,
|
|
DefaultValue,
|
|
TokenNumber,
|
|
'',
|
|
{},
|
|
False,
|
|
None,
|
|
list(validateranges),
|
|
list(validlists),
|
|
list(expressions)
|
|
)
|
|
DefinitionPosition[PcdObj] = (self.MetaFile.File, LineNo)
|
|
if "." in TokenSpaceGuid:
|
|
StrPcdSet.append((PcdObj, LineNo))
|
|
else:
|
|
Pcds[PcdCName, TokenSpaceGuid, self._PCD_TYPE_STRING_[Type]] = PcdObj
|
|
|
|
StructurePcds = self.ProcessStructurePcd(StrPcdSet)
|
|
for pcd in StructurePcds:
|
|
Pcds[pcd.TokenCName, pcd.TokenSpaceGuidCName, self._PCD_TYPE_STRING_[Type]] = pcd
|
|
StructPattern = compile(r'[_a-zA-Z][0-9A-Za-z_]*$')
|
|
for pcd in Pcds.values():
|
|
if pcd.DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]:
|
|
if not pcd.IsAggregateDatumType():
|
|
EdkLogger.error('build', FORMAT_INVALID, "DatumType only support BOOLEAN, UINT8, UINT16, UINT32, UINT64, VOID* or a valid struct name.", DefinitionPosition[pcd][0], DefinitionPosition[pcd][1])
|
|
elif not pcd.IsArray() and not pcd.StructuredPcdIncludeFile:
|
|
EdkLogger.error("build", PCD_STRUCTURE_PCD_ERROR, "The structure Pcd %s.%s header file is not found in %s line %s \n" % (pcd.TokenSpaceGuidCName, pcd.TokenCName, pcd.DefinitionPosition[0], pcd.DefinitionPosition[1] ))
|
|
return Pcds
|
|
|
|
@property
|
|
def CommonIncludes(self):
|
|
if self._CommonIncludes is None:
|
|
self.Includes
|
|
return self._CommonIncludes
|