]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/BuildReport.py
BaseTools: Fixed build failure when using python38
[mirror_edk2.git] / BaseTools / Source / Python / build / BuildReport.py
CommitLineData
52302d4d
LG
1## @file\r
2# Routines for generating build report.\r
3#\r
4# This module contains the functionality to generate build report after\r
5# build all target completes successfully.\r
6#\r
779ddcdf 7# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>\r
2e351cbe 8# SPDX-License-Identifier: BSD-2-Clause-Patent\r
52302d4d
LG
9#\r
10\r
11## Import Modules\r
12#\r
1be2ed90 13import Common.LongFilePathOs as os\r
52302d4d
LG
14import re\r
15import platform\r
16import textwrap\r
17import traceback\r
18import sys\r
40d841f6 19import time\r
e56468c0 20import struct\r
eca5be7a
YZ
21import hashlib\r
22import subprocess\r
23import threading\r
52302d4d 24from datetime import datetime\r
1ccc4d89 25from io import BytesIO\r
52302d4d 26from Common import EdkLogger\r
40d841f6 27from Common.Misc import SaveFileOnChange\r
52302d4d
LG
28from Common.Misc import GuidStructureByteArrayToGuidString\r
29from Common.Misc import GuidStructureStringToGuidString\r
52302d4d
LG
30from Common.BuildToolError import FILE_WRITE_FAILURE\r
31from Common.BuildToolError import CODE_ERROR\r
eca5be7a 32from Common.BuildToolError import COMMAND_FAILURE\r
35f613d9 33from Common.BuildToolError import FORMAT_INVALID\r
1be2ed90 34from Common.LongFilePathSupport import OpenLongFilePath as open\r
05cc51ad 35from Common.MultipleWorkspace import MultipleWorkspace as mws\r
763e8edf 36import Common.GlobalData as GlobalData\r
e8449e1d 37from AutoGen.ModuleAutoGen import ModuleAutoGen\r
25193a33 38from Common.Misc import PathClass\r
5a57246e 39from Common.StringUtils import NormPath\r
e651d06c
LG
40from Common.DataType import *\r
41import collections\r
35f613d9 42from Common.Expression import *\r
9e47e6f9 43from GenFds.AprioriSection import DXE_APRIORI_GUID, PEI_APRIORI_GUID\r
52302d4d
LG
44\r
45## Pattern to extract contents in EDK DXS files\r
46gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)\r
47\r
48## Pattern to find total FV total size, occupied size in flash report intermediate file\r
49gFvTotalSizePattern = re.compile(r"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")\r
50gFvTakenSizePattern = re.compile(r"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")\r
51\r
52## Pattern to find module size and time stamp in module summary report intermediate file\r
53gModuleSizePattern = re.compile(r"MODULE_SIZE = (\d+)")\r
54gTimeStampPattern = re.compile(r"TIME_STAMP = (\d+)")\r
55\r
56## Pattern to find GUID value in flash description files\r
57gPcdGuidPattern = re.compile(r"PCD\((\w+)[.](\w+)\)")\r
58\r
59## Pattern to collect offset, GUID value pair in the flash report intermediate file\r
60gOffsetGuidPattern = re.compile(r"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")\r
61\r
62## Pattern to find module base address and entry point in fixed flash map file\r
63gModulePattern = r"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"\r
64gMapFileItemPattern = re.compile(gModulePattern % {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})\r
65\r
66## Pattern to find all module referenced header files in source files\r
67gIncludePattern = re.compile(r'#include\s*["<]([^">]+)[">]')\r
68gIncludePattern2 = re.compile(r"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")\r
69\r
70## Pattern to find the entry point for EDK module using EDKII Glue library\r
71gGlueLibEntryPoint = re.compile(r"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")\r
72\r
64b2609f
LG
73## Tags for MaxLength of line in report\r
74gLineMaxLength = 120\r
75\r
4afd3d04 76## Tags for end of line in report\r
1ccc4d89 77gEndOfLine = "\r\n"\r
4afd3d04 78\r
52302d4d 79## Tags for section start, end and separator\r
47fea6af
YZ
80gSectionStart = ">" + "=" * (gLineMaxLength - 2) + "<"\r
81gSectionEnd = "<" + "=" * (gLineMaxLength - 2) + ">" + "\n"\r
64b2609f 82gSectionSep = "=" * gLineMaxLength\r
52302d4d
LG
83\r
84## Tags for subsection start, end and separator\r
47fea6af
YZ
85gSubSectionStart = ">" + "-" * (gLineMaxLength - 2) + "<"\r
86gSubSectionEnd = "<" + "-" * (gLineMaxLength - 2) + ">"\r
64b2609f
LG
87gSubSectionSep = "-" * gLineMaxLength\r
88\r
52302d4d
LG
89\r
90## The look up table to map PCD type to pair of report display type and DEC type\r
91gPcdTypeMap = {\r
be409b67
CJ
92 TAB_PCDS_FIXED_AT_BUILD : ('FIXED', TAB_PCDS_FIXED_AT_BUILD),\r
93 TAB_PCDS_PATCHABLE_IN_MODULE: ('PATCH', TAB_PCDS_PATCHABLE_IN_MODULE),\r
94 TAB_PCDS_FEATURE_FLAG : ('FLAG', TAB_PCDS_FEATURE_FLAG),\r
95 TAB_PCDS_DYNAMIC : ('DYN', TAB_PCDS_DYNAMIC),\r
96 TAB_PCDS_DYNAMIC_HII : ('DYNHII', TAB_PCDS_DYNAMIC),\r
97 TAB_PCDS_DYNAMIC_VPD : ('DYNVPD', TAB_PCDS_DYNAMIC),\r
98 TAB_PCDS_DYNAMIC_EX : ('DEX', TAB_PCDS_DYNAMIC_EX),\r
99 TAB_PCDS_DYNAMIC_EX_HII : ('DEXHII', TAB_PCDS_DYNAMIC_EX),\r
100 TAB_PCDS_DYNAMIC_EX_VPD : ('DEXVPD', TAB_PCDS_DYNAMIC_EX),\r
52302d4d
LG
101 }\r
102\r
103## The look up table to map module type to driver type\r
104gDriverTypeMap = {\r
8bb63e37
CJ
105 SUP_MODULE_SEC : '0x3 (SECURITY_CORE)',\r
106 SUP_MODULE_PEI_CORE : '0x4 (PEI_CORE)',\r
107 SUP_MODULE_PEIM : '0x6 (PEIM)',\r
108 SUP_MODULE_DXE_CORE : '0x5 (DXE_CORE)',\r
109 SUP_MODULE_DXE_DRIVER : '0x7 (DRIVER)',\r
110 SUP_MODULE_DXE_SAL_DRIVER : '0x7 (DRIVER)',\r
111 SUP_MODULE_DXE_SMM_DRIVER : '0x7 (DRIVER)',\r
112 SUP_MODULE_DXE_RUNTIME_DRIVER: '0x7 (DRIVER)',\r
113 SUP_MODULE_UEFI_DRIVER : '0x7 (DRIVER)',\r
114 SUP_MODULE_UEFI_APPLICATION : '0x9 (APPLICATION)',\r
115 SUP_MODULE_SMM_CORE : '0xD (SMM_CORE)',\r
52302d4d 116 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers\r
8bb63e37
CJ
117 SUP_MODULE_MM_STANDALONE : '0xE (MM_STANDALONE)',\r
118 SUP_MODULE_MM_CORE_STANDALONE : '0xF (MM_CORE_STANDALONE)'\r
52302d4d
LG
119 }\r
120\r
e56468c0 121## The look up table of the supported opcode in the dependency expression binaries\r
122gOpCodeList = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]\r
123\r
ebed920f
YZ
124## Save VPD Pcd\r
125VPDPcdList = []\r
126\r
52302d4d
LG
127##\r
128# Writes a string to the file object.\r
129#\r
130# This function writes a string to the file object and a new line is appended\r
131# afterwards. It may optionally wraps the string for better readability.\r
132#\r
133# @File The file object to write\r
134# @String The string to be written to the file\r
135# @Wrapper Indicates whether to wrap the string\r
136#\r
137def FileWrite(File, String, Wrapper=False):\r
138 if Wrapper:\r
139 String = textwrap.fill(String, 120)\r
d943b0c3 140 File.append(String + gEndOfLine)\r
52302d4d 141\r
e651d06c
LG
142def ByteArrayForamt(Value):\r
143 IsByteArray = False\r
144 SplitNum = 16\r
145 ArrayList = []\r
9f30e401 146 if Value.startswith('{') and Value.endswith('}') and not Value.startswith("{CODE("):\r
e651d06c
LG
147 Value = Value[1:-1]\r
148 ValueList = Value.split(',')\r
149 if len(ValueList) >= SplitNum:\r
150 IsByteArray = True\r
151 if IsByteArray:\r
152 if ValueList:\r
153 Len = len(ValueList)/SplitNum\r
154 for i, element in enumerate(ValueList):\r
155 ValueList[i] = '0x%02X' % int(element.strip(), 16)\r
156 if Len:\r
157 Id = 0\r
158 while (Id <= Len):\r
159 End = min(SplitNum*(Id+1), len(ValueList))\r
160 Str = ','.join(ValueList[SplitNum*Id : End])\r
161 if End == len(ValueList):\r
162 Str += '}'\r
163 ArrayList.append(Str)\r
164 break\r
165 else:\r
166 Str += ','\r
167 ArrayList.append(Str)\r
168 Id += 1\r
169 else:\r
170 ArrayList = [Value + '}']\r
171 return IsByteArray, ArrayList\r
172\r
52302d4d
LG
173##\r
174# Find all the header file that the module source directly includes.\r
175#\r
176# This function scans source code to find all header files the module may\r
177# include. This is not accurate but very effective to find all the header\r
178# file the module might include with #include statement.\r
179#\r
180# @Source The source file name\r
181# @IncludePathList The list of include path to find the source file.\r
182# @IncludeFiles The dictionary of current found include files.\r
183#\r
184def FindIncludeFiles(Source, IncludePathList, IncludeFiles):\r
185 FileContents = open(Source).read()\r
186 #\r
187 # Find header files with pattern #include "XXX.h" or #include <XXX.h>\r
188 #\r
189 for Match in gIncludePattern.finditer(FileContents):\r
190 FileName = Match.group(1).strip()\r
191 for Dir in [os.path.dirname(Source)] + IncludePathList:\r
192 FullFileName = os.path.normpath(os.path.join(Dir, FileName))\r
193 if os.path.exists(FullFileName):\r
194 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName\r
195 break\r
196\r
197 #\r
198 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)\r
199 #\r
200 for Match in gIncludePattern2.finditer(FileContents):\r
201 Key = Match.group(2)\r
202 Type = Match.group(1)\r
203 if "ARCH_PROTOCOL" in Type:\r
204 FileName = "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
205 elif "PROTOCOL" in Type:\r
206 FileName = "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
207 elif "PPI" in Type:\r
208 FileName = "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
91fa33ee 209 elif TAB_GUID in Type:\r
52302d4d
LG
210 FileName = "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
211 else:\r
212 continue\r
213 for Dir in IncludePathList:\r
214 FullFileName = os.path.normpath(os.path.join(Dir, FileName))\r
215 if os.path.exists(FullFileName):\r
216 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName\r
217 break\r
218\r
64b2609f
LG
219## Split each lines in file\r
220#\r
f7496d71 221# This method is used to split the lines in file to make the length of each line\r
64b2609f
LG
222# less than MaxLength.\r
223#\r
224# @param Content The content of file\r
225# @param MaxLength The Max Length of the line\r
226#\r
227def FileLinesSplit(Content=None, MaxLength=None):\r
228 ContentList = Content.split(TAB_LINE_BREAK)\r
229 NewContent = ''\r
230 NewContentList = []\r
231 for Line in ContentList:\r
232 while len(Line.rstrip()) > MaxLength:\r
233 LineSpaceIndex = Line.rfind(TAB_SPACE_SPLIT, 0, MaxLength)\r
234 LineSlashIndex = Line.rfind(TAB_SLASH, 0, MaxLength)\r
25918452
LG
235 LineBackSlashIndex = Line.rfind(TAB_BACK_SLASH, 0, MaxLength)\r
236 if max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex) > 0:\r
237 LineBreakIndex = max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex)\r
238 else:\r
239 LineBreakIndex = MaxLength\r
64b2609f
LG
240 NewContentList.append(Line[:LineBreakIndex])\r
241 Line = Line[LineBreakIndex:]\r
242 if Line:\r
243 NewContentList.append(Line)\r
244 for NewLine in NewContentList:\r
245 NewContent += NewLine + TAB_LINE_BREAK\r
f7496d71 246\r
30e65c4e 247 NewContent = NewContent.replace(gEndOfLine, TAB_LINE_BREAK).replace('\r\r\n', gEndOfLine)\r
64b2609f 248 return NewContent\r
f7496d71
LG
249\r
250\r
251\r
e56468c0 252##\r
253# Parse binary dependency expression section\r
254#\r
255# This utility class parses the dependency expression section and translate the readable\r
256# GUID name and value.\r
257#\r
258class DepexParser(object):\r
259 ##\r
260 # Constructor function for class DepexParser\r
261 #\r
262 # This constructor function collect GUID values so that the readable\r
263 # GUID name can be translated.\r
264 #\r
265 # @param self The object pointer\r
266 # @param Wa Workspace context information\r
267 #\r
268 def __init__(self, Wa):\r
269 self._GuidDb = {}\r
0d2711a6 270 for Pa in Wa.AutoGenObjectList:\r
47fea6af 271 for Package in Pa.PackageList:\r
0d2711a6
LG
272 for Protocol in Package.Protocols:\r
273 GuidValue = GuidStructureStringToGuidString(Package.Protocols[Protocol])\r
274 self._GuidDb[GuidValue.upper()] = Protocol\r
275 for Ppi in Package.Ppis:\r
276 GuidValue = GuidStructureStringToGuidString(Package.Ppis[Ppi])\r
277 self._GuidDb[GuidValue.upper()] = Ppi\r
278 for Guid in Package.Guids:\r
279 GuidValue = GuidStructureStringToGuidString(Package.Guids[Guid])\r
280 self._GuidDb[GuidValue.upper()] = Guid\r
a10def91
YF
281 for Ma in Pa.ModuleAutoGenList:\r
282 for Pcd in Ma.FixedVoidTypePcds:\r
283 PcdValue = Ma.FixedVoidTypePcds[Pcd]\r
284 if len(PcdValue.split(',')) == 16:\r
285 GuidValue = GuidStructureByteArrayToGuidString(PcdValue)\r
286 self._GuidDb[GuidValue.upper()] = Pcd\r
e56468c0 287 ##\r
288 # Parse the binary dependency expression files.\r
f7496d71 289 #\r
e56468c0 290 # This function parses the binary dependency expression file and translate it\r
291 # to the instruction list.\r
292 #\r
293 # @param self The object pointer\r
294 # @param DepexFileName The file name of binary dependency expression file.\r
295 #\r
296 def ParseDepexFile(self, DepexFileName):\r
297 DepexFile = open(DepexFileName, "rb")\r
298 DepexStatement = []\r
299 OpCode = DepexFile.read(1)\r
300 while OpCode:\r
301 Statement = gOpCodeList[struct.unpack("B", OpCode)[0]]\r
302 if Statement in ["BEFORE", "AFTER", "PUSH"]:\r
303 GuidValue = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \\r
d0a0c52c 304 struct.unpack(PACK_PATTERN_GUID, DepexFile.read(16))\r
e56468c0 305 GuidString = self._GuidDb.get(GuidValue, GuidValue)\r
306 Statement = "%s %s" % (Statement, GuidString)\r
307 DepexStatement.append(Statement)\r
47fea6af
YZ
308 OpCode = DepexFile.read(1)\r
309\r
e56468c0 310 return DepexStatement\r
f7496d71 311\r
52302d4d
LG
312##\r
313# Reports library information\r
314#\r
315# This class reports the module library subsection in the build report file.\r
316#\r
317class LibraryReport(object):\r
318 ##\r
319 # Constructor function for class LibraryReport\r
320 #\r
321 # This constructor function generates LibraryReport object for\r
322 # a module.\r
323 #\r
324 # @param self The object pointer\r
325 # @param M Module context information\r
326 #\r
327 def __init__(self, M):\r
328 self.LibraryList = []\r
52302d4d
LG
329\r
330 for Lib in M.DependentLibraryList:\r
331 LibInfPath = str(Lib)\r
332 LibClassList = Lib.LibraryClass[0].LibraryClass\r
333 LibConstructorList = Lib.ConstructorList\r
334 LibDesstructorList = Lib.DestructorList\r
335 LibDepexList = Lib.DepexExpression[M.Arch, M.ModuleType]\r
1b8eca8b
YZ
336 for LibAutoGen in M.LibraryAutoGenList:\r
337 if LibInfPath == LibAutoGen.MetaFile.Path:\r
338 LibTime = LibAutoGen.BuildTime\r
339 break\r
340 self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList, LibTime))\r
52302d4d
LG
341\r
342 ##\r
343 # Generate report for module library information\r
344 #\r
345 # This function generates report for the module library.\r
346 # If the module is EDKII style one, the additional library class, library\r
347 # constructor/destructor and dependency expression may also be reported.\r
348 #\r
349 # @param self The object pointer\r
350 # @param File The file object for report\r
351 #\r
352 def GenerateReport(self, File):\r
52302d4d 353 if len(self.LibraryList) > 0:\r
c2d0a1f6
YZ
354 FileWrite(File, gSubSectionStart)\r
355 FileWrite(File, TAB_BRG_LIBRARY)\r
52302d4d
LG
356 FileWrite(File, gSubSectionSep)\r
357 for LibraryItem in self.LibraryList:\r
358 LibInfPath = LibraryItem[0]\r
359 FileWrite(File, LibInfPath)\r
360\r
82292501
FB
361 LibClass = LibraryItem[1]\r
362 EdkIILibInfo = ""\r
363 LibConstructor = " ".join(LibraryItem[2])\r
364 if LibConstructor:\r
365 EdkIILibInfo += " C = " + LibConstructor\r
366 LibDestructor = " ".join(LibraryItem[3])\r
367 if LibDestructor:\r
368 EdkIILibInfo += " D = " + LibDestructor\r
369 LibDepex = " ".join(LibraryItem[4])\r
370 if LibDepex:\r
371 EdkIILibInfo += " Depex = " + LibDepex\r
372 if LibraryItem[5]:\r
373 EdkIILibInfo += " Time = " + LibraryItem[5]\r
374 if EdkIILibInfo:\r
375 FileWrite(File, "{%s: %s}" % (LibClass, EdkIILibInfo))\r
376 else:\r
377 FileWrite(File, "{%s}" % LibClass)\r
52302d4d 378\r
c2d0a1f6 379 FileWrite(File, gSubSectionEnd)\r
52302d4d
LG
380\r
381##\r
382# Reports dependency expression information\r
383#\r
384# This class reports the module dependency expression subsection in the build report file.\r
385#\r
386class DepexReport(object):\r
387 ##\r
388 # Constructor function for class DepexReport\r
389 #\r
390 # This constructor function generates DepexReport object for\r
391 # a module. If the module source contains the DXS file (usually EDK\r
392 # style module), it uses the dependency in DXS file; otherwise,\r
393 # it uses the dependency expression from its own INF [Depex] section\r
394 # and then merges with the ones from its dependent library INF.\r
395 #\r
396 # @param self The object pointer\r
397 # @param M Module context information\r
398 #\r
399 def __init__(self, M):\r
400 self.Depex = ""\r
47fea6af 401 self._DepexFileName = os.path.join(M.BuildDir, "OUTPUT", M.Module.BaseName + ".depex")\r
52302d4d
LG
402 ModuleType = M.ModuleType\r
403 if not ModuleType:\r
ee1ca53d 404 ModuleType = COMPONENT_TO_MODULE_MAP_DICT.get(M.ComponentType, "")\r
636f2be6 405\r
8bb63e37 406 if ModuleType in [SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_DXE_CORE, SUP_MODULE_SMM_CORE, SUP_MODULE_MM_CORE_STANDALONE, SUP_MODULE_UEFI_APPLICATION]:\r
52302d4d 407 return\r
f7496d71 408\r
52302d4d
LG
409 for Source in M.SourceFileList:\r
410 if os.path.splitext(Source.Path)[1].lower() == ".dxs":\r
411 Match = gDxsDependencyPattern.search(open(Source.Path).read())\r
412 if Match:\r
413 self.Depex = Match.group(1).strip()\r
414 self.Source = "DXS"\r
415 break\r
416 else:\r
caf74495 417 self.Depex = M.DepexExpressionDict.get(M.ModuleType, "")\r
52302d4d
LG
418 self.ModuleDepex = " ".join(M.Module.DepexExpression[M.Arch, M.ModuleType])\r
419 if not self.ModuleDepex:\r
420 self.ModuleDepex = "(None)"\r
421\r
422 LibDepexList = []\r
423 for Lib in M.DependentLibraryList:\r
424 LibDepex = " ".join(Lib.DepexExpression[M.Arch, M.ModuleType]).strip()\r
425 if LibDepex != "":\r
426 LibDepexList.append("(" + LibDepex + ")")\r
427 self.LibraryDepex = " AND ".join(LibDepexList)\r
428 if not self.LibraryDepex:\r
429 self.LibraryDepex = "(None)"\r
430 self.Source = "INF"\r
431\r
432 ##\r
433 # Generate report for module dependency expression information\r
434 #\r
435 # This function generates report for the module dependency expression.\r
436 #\r
e56468c0 437 # @param self The object pointer\r
438 # @param File The file object for report\r
439 # @param GlobalDepexParser The platform global Dependency expression parser object\r
52302d4d 440 #\r
e56468c0 441 def GenerateReport(self, File, GlobalDepexParser):\r
52302d4d
LG
442 if not self.Depex:\r
443 return\r
52302d4d 444 FileWrite(File, gSubSectionStart)\r
e56468c0 445 if os.path.isfile(self._DepexFileName):\r
446 try:\r
447 DepexStatements = GlobalDepexParser.ParseDepexFile(self._DepexFileName)\r
448 FileWrite(File, "Final Dependency Expression (DEPEX) Instructions")\r
449 for DepexStatement in DepexStatements:\r
450 FileWrite(File, " %s" % DepexStatement)\r
451 FileWrite(File, gSubSectionSep)\r
452 except:\r
453 EdkLogger.warn(None, "Dependency expression file is corrupted", self._DepexFileName)\r
f7496d71 454\r
52302d4d
LG
455 FileWrite(File, "Dependency Expression (DEPEX) from %s" % self.Source)\r
456\r
457 if self.Source == "INF":\r
caf74495 458 FileWrite(File, self.Depex, True)\r
52302d4d
LG
459 FileWrite(File, gSubSectionSep)\r
460 FileWrite(File, "From Module INF: %s" % self.ModuleDepex, True)\r
461 FileWrite(File, "From Library INF: %s" % self.LibraryDepex, True)\r
462 else:\r
caf74495 463 FileWrite(File, self.Depex)\r
52302d4d
LG
464 FileWrite(File, gSubSectionEnd)\r
465\r
466##\r
467# Reports dependency expression information\r
468#\r
469# This class reports the module build flags subsection in the build report file.\r
470#\r
471class BuildFlagsReport(object):\r
472 ##\r
473 # Constructor function for class BuildFlagsReport\r
474 #\r
475 # This constructor function generates BuildFlagsReport object for\r
476 # a module. It reports the build tool chain tag and all relevant\r
477 # build flags to build the module.\r
478 #\r
479 # @param self The object pointer\r
480 # @param M Module context information\r
481 #\r
482 def __init__(self, M):\r
483 BuildOptions = {}\r
484 #\r
485 # Add build flags according to source file extension so that\r
486 # irrelevant ones can be filtered out.\r
487 #\r
488 for Source in M.SourceFileList:\r
489 Ext = os.path.splitext(Source.File)[1].lower()\r
490 if Ext in [".c", ".cc", ".cpp"]:\r
491 BuildOptions["CC"] = 1\r
492 elif Ext in [".s", ".asm"]:\r
493 BuildOptions["PP"] = 1\r
494 BuildOptions["ASM"] = 1\r
495 elif Ext in [".vfr"]:\r
496 BuildOptions["VFRPP"] = 1\r
497 BuildOptions["VFR"] = 1\r
498 elif Ext in [".dxs"]:\r
499 BuildOptions["APP"] = 1\r
500 BuildOptions["CC"] = 1\r
501 elif Ext in [".asl"]:\r
502 BuildOptions["ASLPP"] = 1\r
503 BuildOptions["ASL"] = 1\r
504 elif Ext in [".aslc"]:\r
505 BuildOptions["ASLCC"] = 1\r
506 BuildOptions["ASLDLINK"] = 1\r
507 BuildOptions["CC"] = 1\r
508 elif Ext in [".asm16"]:\r
509 BuildOptions["ASMLINK"] = 1\r
510 BuildOptions["SLINK"] = 1\r
511 BuildOptions["DLINK"] = 1\r
512\r
513 #\r
514 # Save module build flags.\r
515 #\r
516 self.ToolChainTag = M.ToolChain\r
517 self.BuildFlags = {}\r
518 for Tool in BuildOptions:\r
519 self.BuildFlags[Tool + "_FLAGS"] = M.BuildOption.get(Tool, {}).get("FLAGS", "")\r
520\r
521 ##\r
522 # Generate report for module build flags information\r
523 #\r
524 # This function generates report for the module build flags expression.\r
525 #\r
526 # @param self The object pointer\r
527 # @param File The file object for report\r
528 #\r
529 def GenerateReport(self, File):\r
530 FileWrite(File, gSubSectionStart)\r
531 FileWrite(File, "Build Flags")\r
532 FileWrite(File, "Tool Chain Tag: %s" % self.ToolChainTag)\r
533 for Tool in self.BuildFlags:\r
534 FileWrite(File, gSubSectionSep)\r
535 FileWrite(File, "%s = %s" % (Tool, self.BuildFlags[Tool]), True)\r
536\r
537 FileWrite(File, gSubSectionEnd)\r
538\r
539\r
540##\r
541# Reports individual module information\r
542#\r
543# This class reports the module section in the build report file.\r
544# It comprises of module summary, module PCD, library, dependency expression,\r
545# build flags sections.\r
546#\r
547class ModuleReport(object):\r
548 ##\r
549 # Constructor function for class ModuleReport\r
550 #\r
551 # This constructor function generates ModuleReport object for\r
552 # a separate module in a platform build.\r
553 #\r
554 # @param self The object pointer\r
555 # @param M Module context information\r
556 # @param ReportType The kind of report items in the final report file\r
557 #\r
558 def __init__(self, M, ReportType):\r
559 self.ModuleName = M.Module.BaseName\r
560 self.ModuleInfPath = M.MetaFile.File\r
101dc9e2 561 self.ModuleArch = M.Arch\r
52302d4d
LG
562 self.FileGuid = M.Guid\r
563 self.Size = 0\r
564 self.BuildTimeStamp = None\r
eca5be7a 565 self.Hash = 0\r
52302d4d 566 self.DriverType = ""\r
636f2be6
LG
567 if not M.IsLibrary:\r
568 ModuleType = M.ModuleType\r
569 if not ModuleType:\r
ee1ca53d 570 ModuleType = COMPONENT_TO_MODULE_MAP_DICT.get(M.ComponentType, "")\r
636f2be6
LG
571 #\r
572 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"\r
573 #\r
8bb63e37 574 if ModuleType == SUP_MODULE_DXE_SMM_DRIVER:\r
47fea6af 575 PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000")\r
0d2711a6 576 if int(PiSpec, 0) >= 0x0001000A:\r
636f2be6
LG
577 ModuleType = "SMM_DRIVER"\r
578 self.DriverType = gDriverTypeMap.get(ModuleType, "0x2 (FREE_FORM)")\r
52302d4d
LG
579 self.UefiSpecVersion = M.Module.Specification.get("UEFI_SPECIFICATION_VERSION", "")\r
580 self.PiSpecVersion = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "")\r
581 self.PciDeviceId = M.Module.Defines.get("PCI_DEVICE_ID", "")\r
582 self.PciVendorId = M.Module.Defines.get("PCI_VENDOR_ID", "")\r
583 self.PciClassCode = M.Module.Defines.get("PCI_CLASS_CODE", "")\r
1b8eca8b 584 self.BuildTime = M.BuildTime\r
52302d4d
LG
585\r
586 self._BuildDir = M.BuildDir\r
587 self.ModulePcdSet = {}\r
588 if "PCD" in ReportType:\r
589 #\r
590 # Collect all module used PCD set: module INF referenced directly or indirectly.\r
591 # It also saves module INF default values of them in case they exist.\r
592 #\r
1ccc4d89 593 for Pcd in M.ModulePcdList + M.LibraryPcdList:\r
52302d4d
LG
594 self.ModulePcdSet.setdefault((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Type), (Pcd.InfDefaultValue, Pcd.DefaultValue))\r
595\r
596 self.LibraryReport = None\r
597 if "LIBRARY" in ReportType:\r
598 self.LibraryReport = LibraryReport(M)\r
599\r
600 self.DepexReport = None\r
601 if "DEPEX" in ReportType:\r
602 self.DepexReport = DepexReport(M)\r
603\r
604 if "BUILD_FLAGS" in ReportType:\r
605 self.BuildFlagsReport = BuildFlagsReport(M)\r
606\r
607\r
608 ##\r
609 # Generate report for module information\r
610 #\r
611 # This function generates report for separate module expression\r
612 # in a platform build.\r
613 #\r
e56468c0 614 # @param self The object pointer\r
615 # @param File The file object for report\r
616 # @param GlobalPcdReport The platform global PCD report object\r
617 # @param GlobalPredictionReport The platform global Prediction report object\r
618 # @param GlobalDepexParser The platform global Dependency expression parser object\r
619 # @param ReportType The kind of report items in the final report file\r
52302d4d 620 #\r
e56468c0 621 def GenerateReport(self, File, GlobalPcdReport, GlobalPredictionReport, GlobalDepexParser, ReportType):\r
52302d4d
LG
622 FileWrite(File, gSectionStart)\r
623\r
c648e905 624 FwReportFileName = os.path.join(self._BuildDir, "OUTPUT", self.ModuleName + ".txt")\r
52302d4d
LG
625 if os.path.isfile(FwReportFileName):\r
626 try:\r
1ccc4d89 627 FileContents = open(FwReportFileName).read()\r
52302d4d
LG
628 Match = gModuleSizePattern.search(FileContents)\r
629 if Match:\r
630 self.Size = int(Match.group(1))\r
631\r
632 Match = gTimeStampPattern.search(FileContents)\r
633 if Match:\r
d943b0c3 634 self.BuildTimeStamp = datetime.utcfromtimestamp(int(Match.group(1)))\r
52302d4d
LG
635 except IOError:\r
636 EdkLogger.warn(None, "Fail to read report file", FwReportFileName)\r
637\r
eca5be7a
YZ
638 if "HASH" in ReportType:\r
639 OutputDir = os.path.join(self._BuildDir, "OUTPUT")\r
640 DefaultEFIfile = os.path.join(OutputDir, self.ModuleName + ".efi")\r
641 if os.path.isfile(DefaultEFIfile):\r
642 Tempfile = os.path.join(OutputDir, self.ModuleName + "_hash.tmp")\r
643 # rebase the efi image since its base address may not zero\r
644 cmd = ["GenFw", "--rebase", str(0), "-o", Tempfile, DefaultEFIfile]\r
645 try:\r
646 PopenObject = subprocess.Popen(' '.join(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)\r
5b0671c1 647 except Exception as X:\r
eca5be7a
YZ
648 EdkLogger.error("GenFw", COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0]))\r
649 EndOfProcedure = threading.Event()\r
650 EndOfProcedure.clear()\r
651 if PopenObject.stderr:\r
652 StdErrThread = threading.Thread(target=ReadMessage, args=(PopenObject.stderr, EdkLogger.quiet, EndOfProcedure))\r
653 StdErrThread.setName("STDERR-Redirector")\r
654 StdErrThread.setDaemon(False)\r
655 StdErrThread.start()\r
656 # waiting for program exit\r
657 PopenObject.wait()\r
658 if PopenObject.stderr:\r
659 StdErrThread.join()\r
660 if PopenObject.returncode != 0:\r
661 EdkLogger.error("GenFw", COMMAND_FAILURE, "Failed to generate firmware hash image for %s" % (DefaultEFIfile))\r
662 if os.path.isfile(Tempfile):\r
663 self.Hash = hashlib.sha1()\r
664 buf = open(Tempfile, 'rb').read()\r
665 if self.Hash.update(buf):\r
666 self.Hash = self.Hash.update(buf)\r
667 self.Hash = self.Hash.hexdigest()\r
668 os.remove(Tempfile)\r
669\r
52302d4d
LG
670 FileWrite(File, "Module Summary")\r
671 FileWrite(File, "Module Name: %s" % self.ModuleName)\r
101dc9e2 672 FileWrite(File, "Module Arch: %s" % self.ModuleArch)\r
52302d4d
LG
673 FileWrite(File, "Module INF Path: %s" % self.ModuleInfPath)\r
674 FileWrite(File, "File GUID: %s" % self.FileGuid)\r
675 if self.Size:\r
676 FileWrite(File, "Size: 0x%X (%.2fK)" % (self.Size, self.Size / 1024.0))\r
eca5be7a
YZ
677 if self.Hash:\r
678 FileWrite(File, "SHA1 HASH: %s *%s" % (self.Hash, self.ModuleName + ".efi"))\r
52302d4d
LG
679 if self.BuildTimeStamp:\r
680 FileWrite(File, "Build Time Stamp: %s" % self.BuildTimeStamp)\r
1b8eca8b
YZ
681 if self.BuildTime:\r
682 FileWrite(File, "Module Build Time: %s" % self.BuildTime)\r
52302d4d
LG
683 if self.DriverType:\r
684 FileWrite(File, "Driver Type: %s" % self.DriverType)\r
685 if self.UefiSpecVersion:\r
686 FileWrite(File, "UEFI Spec Version: %s" % self.UefiSpecVersion)\r
687 if self.PiSpecVersion:\r
688 FileWrite(File, "PI Spec Version: %s" % self.PiSpecVersion)\r
689 if self.PciDeviceId:\r
690 FileWrite(File, "PCI Device ID: %s" % self.PciDeviceId)\r
691 if self.PciVendorId:\r
692 FileWrite(File, "PCI Vendor ID: %s" % self.PciVendorId)\r
693 if self.PciClassCode:\r
694 FileWrite(File, "PCI Class Code: %s" % self.PciClassCode)\r
695\r
696 FileWrite(File, gSectionSep)\r
697\r
698 if "PCD" in ReportType:\r
699 GlobalPcdReport.GenerateReport(File, self.ModulePcdSet)\r
700\r
701 if "LIBRARY" in ReportType:\r
702 self.LibraryReport.GenerateReport(File)\r
703\r
704 if "DEPEX" in ReportType:\r
e56468c0 705 self.DepexReport.GenerateReport(File, GlobalDepexParser)\r
52302d4d
LG
706\r
707 if "BUILD_FLAGS" in ReportType:\r
708 self.BuildFlagsReport.GenerateReport(File)\r
709\r
710 if "FIXED_ADDRESS" in ReportType and self.FileGuid:\r
711 GlobalPredictionReport.GenerateReport(File, self.FileGuid)\r
712\r
713 FileWrite(File, gSectionEnd)\r
714\r
eca5be7a
YZ
715def ReadMessage(From, To, ExitFlag):\r
716 while True:\r
717 # read one line a time\r
718 Line = From.readline()\r
719 # empty string means "end"\r
d943b0c3
FB
720 if Line is not None and Line != b"":\r
721 To(Line.rstrip().decode(encoding='utf-8', errors='ignore'))\r
eca5be7a
YZ
722 else:\r
723 break\r
724 if ExitFlag.isSet():\r
725 break\r
726\r
52302d4d
LG
727##\r
728# Reports platform and module PCD information\r
729#\r
730# This class reports the platform PCD section and module PCD subsection\r
731# in the build report file.\r
732#\r
733class PcdReport(object):\r
734 ##\r
735 # Constructor function for class PcdReport\r
736 #\r
737 # This constructor function generates PcdReport object a platform build.\r
738 # It collects the whole PCD database from platform DSC files, platform\r
739 # flash description file and package DEC files.\r
740 #\r
741 # @param self The object pointer\r
742 # @param Wa Workspace context information\r
743 #\r
744 def __init__(self, Wa):\r
745 self.AllPcds = {}\r
c8d07c5e
YZ
746 self.UnusedPcds = {}\r
747 self.ConditionalPcds = {}\r
52302d4d 748 self.MaxLen = 0\r
e651d06c 749 self.Arch = None\r
52302d4d
LG
750 if Wa.FdfProfile:\r
751 self.FdfPcdSet = Wa.FdfProfile.PcdDict\r
752 else:\r
753 self.FdfPcdSet = {}\r
754\r
779ddcdf
YZ
755 self.DefaultStoreSingle = True\r
756 self.SkuSingle = True\r
757 if GlobalData.gDefaultStores and len(GlobalData.gDefaultStores) > 1:\r
758 self.DefaultStoreSingle = False\r
759 if GlobalData.gSkuids and len(GlobalData.gSkuids) > 1:\r
760 self.SkuSingle = False\r
761\r
52302d4d
LG
762 self.ModulePcdOverride = {}\r
763 for Pa in Wa.AutoGenObjectList:\r
e651d06c 764 self.Arch = Pa.Arch\r
52302d4d
LG
765 #\r
766 # Collect all platform referenced PCDs and grouped them by PCD token space\r
767 # GUID C Names\r
768 #\r
769 for Pcd in Pa.AllPcdList:\r
770 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
771 if Pcd not in PcdList:\r
772 PcdList.append(Pcd)\r
773 if len(Pcd.TokenCName) > self.MaxLen:\r
774 self.MaxLen = len(Pcd.TokenCName)\r
c8d07c5e
YZ
775 #\r
776 # Collect the PCD defined in DSC/FDF file, but not used in module\r
777 #\r
778 UnusedPcdFullList = []\r
96351721 779 StructPcdDict = GlobalData.gStructurePcd.get(self.Arch, collections.OrderedDict())\r
97c8f5b9
FZ
780 for Name, Guid in StructPcdDict:\r
781 if (Name, Guid) not in Pa.Platform.Pcds:\r
782 Pcd = StructPcdDict[(Name, Guid)]\r
783 PcdList = self.AllPcds.setdefault(Guid, {}).setdefault(Pcd.Type, [])\r
784 if Pcd not in PcdList and Pcd not in UnusedPcdFullList:\r
785 UnusedPcdFullList.append(Pcd)\r
c8d07c5e
YZ
786 for item in Pa.Platform.Pcds:\r
787 Pcd = Pa.Platform.Pcds[item]\r
c65df5d9
YZ
788 if not Pcd.Type:\r
789 # check the Pcd in FDF file, whether it is used in module first\r
be409b67 790 for T in PCD_TYPE_LIST:\r
c65df5d9
YZ
791 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(T, [])\r
792 if Pcd in PcdList:\r
793 Pcd.Type = T\r
794 break\r
c8d07c5e
YZ
795 if not Pcd.Type:\r
796 PcdTypeFlag = False\r
797 for package in Pa.PackageList:\r
be409b67 798 for T in PCD_TYPE_LIST:\r
c8d07c5e
YZ
799 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T) in package.Pcds:\r
800 Pcd.Type = T\r
801 PcdTypeFlag = True\r
802 if not Pcd.DatumType:\r
803 Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T)].DatumType\r
804 break\r
805 if PcdTypeFlag:\r
806 break\r
807 if not Pcd.DatumType:\r
808 PcdType = Pcd.Type\r
809 # Try to remove Hii and Vpd suffix\r
be409b67
CJ
810 if PcdType.startswith(TAB_PCDS_DYNAMIC_EX):\r
811 PcdType = TAB_PCDS_DYNAMIC_EX\r
812 elif PcdType.startswith(TAB_PCDS_DYNAMIC):\r
813 PcdType = TAB_PCDS_DYNAMIC\r
c8d07c5e
YZ
814 for package in Pa.PackageList:\r
815 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType) in package.Pcds:\r
816 Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType)].DatumType\r
817 break\r
818\r
819 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
ac4578af 820 UnusedPcdList = self.UnusedPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
821 if Pcd in UnusedPcdList:\r
822 UnusedPcdList.remove(Pcd)\r
c8d07c5e
YZ
823 if Pcd not in PcdList and Pcd not in UnusedPcdFullList:\r
824 UnusedPcdFullList.append(Pcd)\r
825 if len(Pcd.TokenCName) > self.MaxLen:\r
826 self.MaxLen = len(Pcd.TokenCName)\r
827\r
828 if GlobalData.gConditionalPcds:\r
829 for PcdItem in GlobalData.gConditionalPcds:\r
830 if '.' in PcdItem:\r
831 (TokenSpaceGuidCName, TokenCName) = PcdItem.split('.')\r
9eb87141 832 if (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:\r
c8d07c5e
YZ
833 Pcd = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)]\r
834 PcdList = self.ConditionalPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
835 if Pcd not in PcdList:\r
836 PcdList.append(Pcd)\r
837\r
838 UnusedPcdList = []\r
839 if UnusedPcdFullList:\r
840 for Pcd in UnusedPcdFullList:\r
841 if Pcd.TokenSpaceGuidCName + '.' + Pcd.TokenCName in GlobalData.gConditionalPcds:\r
842 continue\r
843 UnusedPcdList.append(Pcd)\r
844\r
845 for Pcd in UnusedPcdList:\r
846 PcdList = self.UnusedPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
847 if Pcd not in PcdList:\r
848 PcdList.append(Pcd)\r
52302d4d
LG
849\r
850 for Module in Pa.Platform.Modules.values():\r
851 #\r
852 # Collect module override PCDs\r
853 #\r
1ccc4d89 854 for ModulePcd in Module.M.ModulePcdList + Module.M.LibraryPcdList:\r
52302d4d
LG
855 TokenCName = ModulePcd.TokenCName\r
856 TokenSpaceGuid = ModulePcd.TokenSpaceGuidCName\r
857 ModuleDefault = ModulePcd.DefaultValue\r
858 ModulePath = os.path.basename(Module.M.MetaFile.File)\r
859 self.ModulePcdOverride.setdefault((TokenCName, TokenSpaceGuid), {})[ModulePath] = ModuleDefault\r
860\r
861\r
862 #\r
863 # Collect PCD DEC default value.\r
864 #\r
865 self.DecPcdDefault = {}\r
726c501c 866 self._GuidDict = {}\r
0d2711a6
LG
867 for Pa in Wa.AutoGenObjectList:\r
868 for Package in Pa.PackageList:\r
726c501c
YZ
869 Guids = Package.Guids\r
870 self._GuidDict.update(Guids)\r
0d2711a6
LG
871 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
872 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
873 self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)\r
52302d4d
LG
874 #\r
875 # Collect PCDs defined in DSC common section\r
876 #\r
877 self.DscPcdDefault = {}\r
e651d06c
LG
878 for Pa in Wa.AutoGenObjectList:\r
879 for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:\r
643e8e4b 880 DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DscDefaultValue\r
40d841f6
LG
881 if DscDefaultValue:\r
882 self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
52302d4d 883\r
c8d07c5e 884 def GenerateReport(self, File, ModulePcdSet):\r
b91b8ee4
YZ
885 if not ModulePcdSet:\r
886 if self.ConditionalPcds:\r
887 self.GenerateReportDetail(File, ModulePcdSet, 1)\r
888 if self.UnusedPcds:\r
ae57950f 889 IsEmpty = True\r
890 for Token in self.UnusedPcds:\r
891 TokenDict = self.UnusedPcds[Token]\r
892 for Type in TokenDict:\r
893 if TokenDict[Type]:\r
894 IsEmpty = False\r
895 break\r
896 if not IsEmpty:\r
897 break\r
898 if not IsEmpty:\r
899 self.GenerateReportDetail(File, ModulePcdSet, 2)\r
c8d07c5e
YZ
900 self.GenerateReportDetail(File, ModulePcdSet)\r
901\r
52302d4d
LG
902 ##\r
903 # Generate report for PCD information\r
904 #\r
905 # This function generates report for separate module expression\r
906 # in a platform build.\r
907 #\r
908 # @param self The object pointer\r
909 # @param File The file object for report\r
910 # @param ModulePcdSet Set of all PCDs referenced by module or None for\r
911 # platform PCD report\r
c8d07c5e
YZ
912 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional\r
913 # directives section report, 2 means Unused Pcds section report\r
52302d4d
LG
914 # @param DscOverridePcds Module DSC override PCDs set\r
915 #\r
c8d07c5e
YZ
916 def GenerateReportDetail(self, File, ModulePcdSet, ReportSubType = 0):\r
917 PcdDict = self.AllPcds\r
918 if ReportSubType == 1:\r
919 PcdDict = self.ConditionalPcds\r
920 elif ReportSubType == 2:\r
921 PcdDict = self.UnusedPcds\r
922\r
b91b8ee4 923 if not ModulePcdSet:\r
52302d4d 924 FileWrite(File, gSectionStart)\r
c8d07c5e
YZ
925 if ReportSubType == 1:\r
926 FileWrite(File, "Conditional Directives used by the build system")\r
927 elif ReportSubType == 2:\r
928 FileWrite(File, "PCDs not used by modules or in conditional directives")\r
929 else:\r
930 FileWrite(File, "Platform Configuration Database Report")\r
931\r
763e8edf 932 FileWrite(File, " *B - PCD override in the build option")\r
52302d4d
LG
933 FileWrite(File, " *P - Platform scoped PCD override in DSC file")\r
934 FileWrite(File, " *F - Platform scoped PCD override in FDF file")\r
c8d07c5e
YZ
935 if not ReportSubType:\r
936 FileWrite(File, " *M - Module scoped PCD override")\r
52302d4d
LG
937 FileWrite(File, gSectionSep)\r
938 else:\r
c2d0a1f6 939 if not ReportSubType and ModulePcdSet:\r
c8d07c5e
YZ
940 #\r
941 # For module PCD sub-section\r
942 #\r
943 FileWrite(File, gSubSectionStart)\r
944 FileWrite(File, TAB_BRG_PCD)\r
945 FileWrite(File, gSubSectionSep)\r
238d9b5c 946 AllPcdDict = {}\r
c8d07c5e 947 for Key in PcdDict:\r
238d9b5c
YF
948 AllPcdDict[Key] = {}\r
949 for Type in PcdDict[Key]:\r
950 for Pcd in PcdDict[Key][Type]:\r
951 AllPcdDict[Key][(Pcd.TokenCName, Type)] = Pcd\r
952 for Key in sorted(AllPcdDict):\r
52302d4d
LG
953 #\r
954 # Group PCD by their token space GUID C Name\r
955 #\r
956 First = True\r
238d9b5c 957 for PcdTokenCName, Type in sorted(AllPcdDict[Key]):\r
52302d4d
LG
958 #\r
959 # Group PCD by their usage type\r
960 #\r
238d9b5c 961 Pcd = AllPcdDict[Key][(PcdTokenCName, Type)]\r
52302d4d 962 TypeName, DecType = gPcdTypeMap.get(Type, ("", Type))\r
238d9b5c
YF
963 MixedPcdFlag = False\r
964 if GlobalData.MixedPcd:\r
965 for PcdKey in GlobalData.MixedPcd:\r
966 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdKey]:\r
967 PcdTokenCName = PcdKey[0]\r
968 MixedPcdFlag = True\r
969 if MixedPcdFlag and not ModulePcdSet:\r
970 continue\r
971 #\r
972 # Get PCD default value and their override relationship\r
973 #\r
974 DecDefaultValue = self.DecPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, DecType))\r
975 DscDefaultValue = self.DscPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))\r
976 DscDefaultValBak = DscDefaultValue\r
5df16ecb
YF
977 Field = ''\r
978 for (CName, Guid, Field) in self.FdfPcdSet:\r
979 if CName == PcdTokenCName and Guid == Key:\r
980 DscDefaultValue = self.FdfPcdSet[(CName, Guid, Field)]\r
981 break\r
238d9b5c
YF
982 if DscDefaultValue != DscDefaultValBak:\r
983 try:\r
984 DscDefaultValue = ValueExpressionEx(DscDefaultValue, Pcd.DatumType, self._GuidDict)(True)\r
5b0671c1 985 except BadExpression as DscDefaultValue:\r
238d9b5c
YF
986 EdkLogger.error('BuildReport', FORMAT_INVALID, "PCD Value: %s, Type: %s" %(DscDefaultValue, Pcd.DatumType))\r
987\r
988 InfDefaultValue = None\r
989\r
990 PcdValue = DecDefaultValue\r
991 if DscDefaultValue:\r
992 PcdValue = DscDefaultValue\r
0fd04efd
ZZ
993 #The DefaultValue of StructurePcd already be the latest, no need to update.\r
994 if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):\r
995 Pcd.DefaultValue = PcdValue\r
238d9b5c
YF
996 if ModulePcdSet is not None:\r
997 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type) not in ModulePcdSet:\r
998 continue\r
5df16ecb 999 InfDefaultValue, PcdValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]\r
0fd04efd
ZZ
1000 #The DefaultValue of StructurePcd already be the latest, no need to update.\r
1001 if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):\r
1002 Pcd.DefaultValue = PcdValue\r
af246402
YF
1003 if InfDefaultValue:\r
1004 try:\r
1005 InfDefaultValue = ValueExpressionEx(InfDefaultValue, Pcd.DatumType, self._GuidDict)(True)\r
1006 except BadExpression as InfDefaultValue:\r
1007 EdkLogger.error('BuildReport', FORMAT_INVALID, "PCD Value: %s, Type: %s" % (InfDefaultValue, Pcd.DatumType))\r
5df16ecb
YF
1008 if InfDefaultValue == "":\r
1009 InfDefaultValue = None\r
238d9b5c
YF
1010\r
1011 BuildOptionMatch = False\r
1012 if GlobalData.BuildOptionPcd:\r
1013 for pcd in GlobalData.BuildOptionPcd:\r
1014 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) == (pcd[0], pcd[1]):\r
1015 if pcd[2]:\r
1016 continue\r
1017 PcdValue = pcd[3]\r
0fd04efd
ZZ
1018 #The DefaultValue of StructurePcd already be the latest, no need to update.\r
1019 if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):\r
1020 Pcd.DefaultValue = PcdValue\r
238d9b5c
YF
1021 BuildOptionMatch = True\r
1022 break\r
763e8edf 1023\r
238d9b5c
YF
1024 if First:\r
1025 if ModulePcdSet is None:\r
1026 FileWrite(File, "")\r
1027 FileWrite(File, Key)\r
1028 First = False\r
52302d4d
LG
1029\r
1030\r
7c41b813 1031 if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:\r
94c91295
ZF
1032 if PcdValue.startswith('0') and not PcdValue.lower().startswith('0x') and \\r
1033 len(PcdValue) > 1 and PcdValue.lstrip('0'):\r
1590d123 1034 PcdValue = PcdValue.lstrip('0')\r
1ccc4d89 1035 PcdValueNumber = int(PcdValue.strip(), 0)\r
238d9b5c
YF
1036 if DecDefaultValue is None:\r
1037 DecMatch = True\r
1038 else:\r
94c91295
ZF
1039 if DecDefaultValue.startswith('0') and not DecDefaultValue.lower().startswith('0x') and \\r
1040 len(DecDefaultValue) > 1 and DecDefaultValue.lstrip('0'):\r
1590d123 1041 DecDefaultValue = DecDefaultValue.lstrip('0')\r
238d9b5c
YF
1042 DecDefaultValueNumber = int(DecDefaultValue.strip(), 0)\r
1043 DecMatch = (DecDefaultValueNumber == PcdValueNumber)\r
52302d4d 1044\r
238d9b5c
YF
1045 if InfDefaultValue is None:\r
1046 InfMatch = True\r
1047 else:\r
94c91295
ZF
1048 if InfDefaultValue.startswith('0') and not InfDefaultValue.lower().startswith('0x') and \\r
1049 len(InfDefaultValue) > 1 and InfDefaultValue.lstrip('0'):\r
1590d123 1050 InfDefaultValue = InfDefaultValue.lstrip('0')\r
238d9b5c
YF
1051 InfDefaultValueNumber = int(InfDefaultValue.strip(), 0)\r
1052 InfMatch = (InfDefaultValueNumber == PcdValueNumber)\r
52302d4d 1053\r
238d9b5c
YF
1054 if DscDefaultValue is None:\r
1055 DscMatch = True\r
52302d4d 1056 else:\r
94c91295
ZF
1057 if DscDefaultValue.startswith('0') and not DscDefaultValue.lower().startswith('0x') and \\r
1058 len(DscDefaultValue) > 1 and DscDefaultValue.lstrip('0'):\r
1590d123 1059 DscDefaultValue = DscDefaultValue.lstrip('0')\r
1ccc4d89 1060 DscDefaultValueNumber = int(DscDefaultValue.strip(), 0)\r
238d9b5c
YF
1061 DscMatch = (DscDefaultValueNumber == PcdValueNumber)\r
1062 else:\r
1063 if DecDefaultValue is None:\r
1064 DecMatch = True\r
1065 else:\r
1066 DecMatch = (DecDefaultValue.strip() == PcdValue.strip())\r
52302d4d 1067\r
238d9b5c
YF
1068 if InfDefaultValue is None:\r
1069 InfMatch = True\r
1070 else:\r
1071 InfMatch = (InfDefaultValue.strip() == PcdValue.strip())\r
52302d4d 1072\r
238d9b5c
YF
1073 if DscDefaultValue is None:\r
1074 DscMatch = True\r
1075 else:\r
1076 DscMatch = (DscDefaultValue.strip() == PcdValue.strip())\r
1077\r
1078 IsStructure = False\r
0fd04efd 1079 if self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):\r
238d9b5c
YF
1080 IsStructure = True\r
1081 if TypeName in ('DYNVPD', 'DEXVPD'):\r
1082 SkuInfoList = Pcd.SkuInfoList\r
1083 Pcd = GlobalData.gStructurePcd[self.Arch][(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)]\r
1084 Pcd.DatumType = Pcd.StructName\r
1085 if TypeName in ('DYNVPD', 'DEXVPD'):\r
1086 Pcd.SkuInfoList = SkuInfoList\r
a6a32677 1087 if Pcd.PcdValueFromComm or Pcd.PcdFieldValueFromComm:\r
238d9b5c
YF
1088 BuildOptionMatch = True\r
1089 DecMatch = False\r
a6a32677
YZ
1090 elif Pcd.PcdValueFromFdf or Pcd.PcdFieldValueFromFdf:\r
1091 DscDefaultValue = True\r
1092 DscMatch = True\r
1093 DecMatch = False\r
238d9b5c
YF
1094 elif Pcd.SkuOverrideValues:\r
1095 DscOverride = False\r
f8811378
YZ
1096 if Pcd.DefaultFromDSC:\r
1097 DscOverride = True\r
52302d4d 1098 else:\r
f8811378
YZ
1099 DictLen = 0\r
1100 for item in Pcd.SkuOverrideValues:\r
1101 DictLen += len(Pcd.SkuOverrideValues[item])\r
1102 if not DictLen:\r
1103 DscOverride = False\r
1104 else:\r
1105 if not Pcd.SkuInfoList:\r
1106 OverrideValues = Pcd.SkuOverrideValues\r
1ccc4d89 1107 if OverrideValues:\r
2c65efac
YZ
1108 for Data in OverrideValues.values():\r
1109 Struct = list(Data.values())\r
1110 if Struct:\r
1111 DscOverride = self.ParseStruct(Struct[0])\r
1112 break\r
f8811378
YZ
1113 else:\r
1114 SkuList = sorted(Pcd.SkuInfoList.keys())\r
1115 for Sku in SkuList:\r
1116 SkuInfo = Pcd.SkuInfoList[Sku]\r
5f094268
FB
1117 if SkuInfo.DefaultStoreDict:\r
1118 DefaultStoreList = sorted(SkuInfo.DefaultStoreDict.keys())\r
1119 for DefaultStore in DefaultStoreList:\r
1120 OverrideValues = Pcd.SkuOverrideValues[Sku]\r
1121 DscOverride = self.ParseStruct(OverrideValues[DefaultStore])\r
1122 if DscOverride:\r
1123 break\r
f8811378
YZ
1124 if DscOverride:\r
1125 break\r
238d9b5c 1126 if DscOverride:\r
39f0156f 1127 DscDefaultValue = True\r
238d9b5c 1128 DscMatch = True\r
e651d06c 1129 DecMatch = False\r
f8811378
YZ
1130 else:\r
1131 DecMatch = True\r
39f0156f
YF
1132 else:\r
1133 DscDefaultValue = True\r
1134 DscMatch = True\r
1135 DecMatch = False\r
238d9b5c
YF
1136\r
1137 #\r
1138 # Report PCD item according to their override relationship\r
1139 #\r
7c41b813 1140 if Pcd.DatumType == 'BOOLEAN':\r
1141 if DscDefaultValue:\r
1142 DscDefaultValue = str(int(DscDefaultValue, 0))\r
1143 if DecDefaultValue:\r
1144 DecDefaultValue = str(int(DecDefaultValue, 0))\r
1145 if InfDefaultValue:\r
1146 InfDefaultValue = str(int(InfDefaultValue, 0))\r
1147 if Pcd.DefaultValue:\r
1148 Pcd.DefaultValue = str(int(Pcd.DefaultValue, 0))\r
5df16ecb 1149 if DecMatch:\r
238d9b5c 1150 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, ' ')\r
5df16ecb
YF
1151 elif InfDefaultValue and InfMatch:\r
1152 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*M')\r
238d9b5c
YF
1153 elif BuildOptionMatch:\r
1154 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*B')\r
1155 else:\r
5df16ecb
YF
1156 if DscDefaultValue and DscMatch:\r
1157 if (Pcd.TokenCName, Key, Field) in self.FdfPcdSet:\r
238d9b5c 1158 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*F')\r
52302d4d 1159 else:\r
238d9b5c
YF
1160 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*P')\r
1161 else:\r
1162 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*M')\r
52302d4d 1163\r
238d9b5c
YF
1164 if ModulePcdSet is None:\r
1165 if IsStructure:\r
1166 continue\r
1167 if not TypeName in ('PATCH', 'FLAG', 'FIXED'):\r
1168 continue\r
1169 if not BuildOptionMatch:\r
1170 ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {})\r
1171 for ModulePath in ModuleOverride:\r
1172 ModuleDefault = ModuleOverride[ModulePath]\r
7c41b813 1173 if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:\r
94c91295
ZF
1174 if ModuleDefault.startswith('0') and not ModuleDefault.lower().startswith('0x') and \\r
1175 len(ModuleDefault) > 1 and ModuleDefault.lstrip('0'):\r
1590d123 1176 ModuleDefault = ModuleDefault.lstrip('0')\r
1ccc4d89 1177 ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)\r
238d9b5c 1178 Match = (ModulePcdDefaultValueNumber == PcdValueNumber)\r
7c41b813 1179 if Pcd.DatumType == 'BOOLEAN':\r
1180 ModuleDefault = str(ModulePcdDefaultValueNumber)\r
238d9b5c
YF
1181 else:\r
1182 Match = (ModuleDefault.strip() == PcdValue.strip())\r
1183 if Match:\r
1184 continue\r
1185 IsByteArray, ArrayList = ByteArrayForamt(ModuleDefault.strip())\r
1186 if IsByteArray:\r
1187 FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 15, ModulePath, '{'))\r
1188 for Array in ArrayList:\r
caf74495 1189 FileWrite(File, Array)\r
238d9b5c 1190 else:\r
cef7ecf6
YF
1191 Value = ModuleDefault.strip()\r
1192 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1193 if Value.startswith(('0x', '0X')):\r
1194 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1195 else:\r
1196 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
1197 FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 15, ModulePath, Value))\r
52302d4d 1198\r
4231a819 1199 if ModulePcdSet is None:\r
52302d4d
LG
1200 FileWrite(File, gSectionEnd)\r
1201 else:\r
c2d0a1f6 1202 if not ReportSubType and ModulePcdSet:\r
c8d07c5e 1203 FileWrite(File, gSubSectionEnd)\r
52302d4d 1204\r
24326f38
YZ
1205 def ParseStruct(self, struct):\r
1206 HasDscOverride = False\r
1207 if struct:\r
f8d11e5a 1208 for _, Values in list(struct.items()):\r
e3ef8f0c
FZ
1209 for Key, value in Values.items():\r
1210 if value[1] and value[1].endswith('.dsc'):\r
1211 HasDscOverride = True\r
1212 break\r
1213 if HasDscOverride == True:\r
24326f38
YZ
1214 break\r
1215 return HasDscOverride\r
52302d4d 1216\r
e651d06c 1217 def PrintPcdDefault(self, File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue):\r
4231a819 1218 if not DscMatch and DscDefaultValue is not None:\r
e651d06c
LG
1219 Value = DscDefaultValue.strip()\r
1220 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1221 if IsByteArray:\r
1222 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', "{"))\r
1223 for Array in ArrayList:\r
caf74495 1224 FileWrite(File, Array)\r
e651d06c 1225 else:\r
179c2f97
YF
1226 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1227 if Value.startswith(('0x', '0X')):\r
1228 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1229 else:\r
1230 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
e651d06c 1231 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', Value))\r
4231a819 1232 if not InfMatch and InfDefaultValue is not None:\r
e651d06c
LG
1233 Value = InfDefaultValue.strip()\r
1234 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1235 if IsByteArray:\r
1236 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', "{"))\r
1237 for Array in ArrayList:\r
caf74495 1238 FileWrite(File, Array)\r
e651d06c 1239 else:\r
179c2f97
YF
1240 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1241 if Value.startswith(('0x', '0X')):\r
1242 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1243 else:\r
1244 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
e651d06c
LG
1245 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', Value))\r
1246\r
4231a819 1247 if not DecMatch and DecDefaultValue is not None:\r
e651d06c
LG
1248 Value = DecDefaultValue.strip()\r
1249 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1250 if IsByteArray:\r
1251 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', "{"))\r
1252 for Array in ArrayList:\r
caf74495 1253 FileWrite(File, Array)\r
e651d06c 1254 else:\r
179c2f97
YF
1255 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1256 if Value.startswith(('0x', '0X')):\r
1257 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1258 else:\r
1ccc4d89 1259 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
e651d06c
LG
1260 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', Value))\r
1261 if IsStructure:\r
350c9ae0
FB
1262 for filedvalues in Pcd.DefaultValues.values():\r
1263 self.PrintStructureInfo(File, filedvalues)\r
24326f38 1264 if DecMatch and IsStructure:\r
350c9ae0
FB
1265 for filedvalues in Pcd.DefaultValues.values():\r
1266 self.PrintStructureInfo(File, filedvalues)\r
e651d06c
LG
1267\r
1268 def PrintPcdValue(self, File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, Flag = ' '):\r
1269 if not Pcd.SkuInfoList:\r
1270 Value = Pcd.DefaultValue\r
1271 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1272 if IsByteArray:\r
1273 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '{'))\r
1274 for Array in ArrayList:\r
caf74495 1275 FileWrite(File, Array)\r
e651d06c 1276 else:\r
179c2f97 1277 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
94c91295 1278 if Value.startswith('0') and not Value.lower().startswith('0x') and len(Value) > 1 and Value.lstrip('0'):\r
1590d123 1279 Value = Value.lstrip('0')\r
ccaa7754 1280 if Value.startswith(('0x', '0X')):\r
179c2f97
YF
1281 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1282 else:\r
1283 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
e651d06c
LG
1284 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))\r
1285 if IsStructure:\r
a6a32677 1286 FiledOverrideFlag = False\r
8a64c7ea
FZ
1287 if (Pcd.TokenCName,Pcd.TokenSpaceGuidCName) in GlobalData.gPcdSkuOverrides:\r
1288 OverrideValues = GlobalData.gPcdSkuOverrides[(Pcd.TokenCName,Pcd.TokenSpaceGuidCName)]\r
1289 else:\r
1290 OverrideValues = Pcd.SkuOverrideValues\r
e651d06c 1291 if OverrideValues:\r
2c65efac
YZ
1292 for Data in OverrideValues.values():\r
1293 Struct = list(Data.values())\r
1294 if Struct:\r
1295 OverrideFieldStruct = self.OverrideFieldValue(Pcd, Struct[0])\r
1296 self.PrintStructureInfo(File, OverrideFieldStruct)\r
a6a32677 1297 FiledOverrideFlag = True\r
2c65efac 1298 break\r
a6a32677
YZ
1299 if not FiledOverrideFlag and (Pcd.PcdFieldValueFromComm or Pcd.PcdFieldValueFromFdf):\r
1300 OverrideFieldStruct = self.OverrideFieldValue(Pcd, {})\r
1301 self.PrintStructureInfo(File, OverrideFieldStruct)\r
e651d06c
LG
1302 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)\r
1303 else:\r
1304 FirstPrint = True\r
1305 SkuList = sorted(Pcd.SkuInfoList.keys())\r
1306 for Sku in SkuList:\r
1307 SkuInfo = Pcd.SkuInfoList[Sku]\r
779ddcdf 1308 SkuIdName = SkuInfo.SkuIdName\r
e651d06c
LG
1309 if TypeName in ('DYNHII', 'DEXHII'):\r
1310 if SkuInfo.DefaultStoreDict:\r
1311 DefaultStoreList = sorted(SkuInfo.DefaultStoreDict.keys())\r
1312 for DefaultStore in DefaultStoreList:\r
1313 Value = SkuInfo.DefaultStoreDict[DefaultStore]\r
1314 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
7c41b813 1315 if Pcd.DatumType == 'BOOLEAN':\r
1316 Value = str(int(Value, 0))\r
e651d06c
LG
1317 if FirstPrint:\r
1318 FirstPrint = False\r
1319 if IsByteArray:\r
779ddcdf
YZ
1320 if self.DefaultStoreSingle and self.SkuSingle:\r
1321 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '{'))\r
1322 elif self.DefaultStoreSingle and not self.SkuSingle:\r
1323 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '{'))\r
1324 elif not self.DefaultStoreSingle and self.SkuSingle:\r
1325 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', '{'))\r
1326 else:\r
1327 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', '{'))\r
e651d06c 1328 for Array in ArrayList:\r
caf74495 1329 FileWrite(File, Array)\r
e651d06c 1330 else:\r
179c2f97
YF
1331 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1332 if Value.startswith(('0x', '0X')):\r
1333 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1334 else:\r
1335 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
779ddcdf
YZ
1336 if self.DefaultStoreSingle and self.SkuSingle:\r
1337 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))\r
1338 elif self.DefaultStoreSingle and not self.SkuSingle:\r
1339 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))\r
1340 elif not self.DefaultStoreSingle and self.SkuSingle:\r
1341 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', Value))\r
1342 else:\r
1343 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', Value))\r
e651d06c
LG
1344 else:\r
1345 if IsByteArray:\r
779ddcdf
YZ
1346 if self.DefaultStoreSingle and self.SkuSingle:\r
1347 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '{'))\r
1348 elif self.DefaultStoreSingle and not self.SkuSingle:\r
1349 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '{'))\r
1350 elif not self.DefaultStoreSingle and self.SkuSingle:\r
1351 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', '{'))\r
1352 else:\r
1353 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', '{'))\r
e651d06c 1354 for Array in ArrayList:\r
caf74495 1355 FileWrite(File, Array)\r
e651d06c 1356 else:\r
179c2f97
YF
1357 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1358 if Value.startswith(('0x', '0X')):\r
1359 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1360 else:\r
1361 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
779ddcdf
YZ
1362 if self.DefaultStoreSingle and self.SkuSingle:\r
1363 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', Value))\r
1364 elif self.DefaultStoreSingle and not self.SkuSingle:\r
1365 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))\r
1366 elif not self.DefaultStoreSingle and self.SkuSingle:\r
1367 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', Value))\r
1368 else:\r
1369 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', Value))\r
e651d06c
LG
1370 FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset))\r
1371 if IsStructure:\r
65eff519 1372 OverrideValues = Pcd.SkuOverrideValues[Sku]\r
24326f38
YZ
1373 OverrideFieldStruct = self.OverrideFieldValue(Pcd, OverrideValues[DefaultStore])\r
1374 self.PrintStructureInfo(File, OverrideFieldStruct)\r
e651d06c 1375 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)\r
e651d06c
LG
1376 else:\r
1377 Value = SkuInfo.DefaultValue\r
1378 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
7c41b813 1379 if Pcd.DatumType == 'BOOLEAN':\r
1380 Value = str(int(Value, 0))\r
e651d06c
LG
1381 if FirstPrint:\r
1382 FirstPrint = False\r
1383 if IsByteArray:\r
779ddcdf
YZ
1384 if self.SkuSingle:\r
1385 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', "{"))\r
1386 else:\r
1387 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', "{"))\r
e651d06c 1388 for Array in ArrayList:\r
caf74495 1389 FileWrite(File, Array)\r
e651d06c 1390 else:\r
179c2f97
YF
1391 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1392 if Value.startswith(('0x', '0X')):\r
1393 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1394 else:\r
1395 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
779ddcdf
YZ
1396 if self.SkuSingle:\r
1397 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))\r
1398 else:\r
1399 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))\r
e651d06c
LG
1400 else:\r
1401 if IsByteArray:\r
779ddcdf 1402 if self.SkuSingle:\r
ccaa7754 1403 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', "{"))\r
779ddcdf 1404 else:\r
ccaa7754 1405 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', "{"))\r
e651d06c 1406 for Array in ArrayList:\r
caf74495 1407 FileWrite(File, Array)\r
e651d06c 1408 else:\r
179c2f97
YF
1409 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1410 if Value.startswith(('0x', '0X')):\r
1411 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1412 else:\r
1413 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
779ddcdf 1414 if self.SkuSingle:\r
ccaa7754 1415 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', Value))\r
779ddcdf 1416 else:\r
ccaa7754 1417 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))\r
779ddcdf
YZ
1418 if TypeName in ('DYNVPD', 'DEXVPD'):\r
1419 FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset))\r
ebed920f
YZ
1420 VPDPcdItem = (Pcd.TokenSpaceGuidCName + '.' + PcdTokenCName, SkuIdName, SkuInfo.VpdOffset, Pcd.MaxDatumSize, SkuInfo.DefaultValue)\r
1421 if VPDPcdItem not in VPDPcdList:\r
85ccbee2
FZ
1422 PcdGuidList = self.UnusedPcds.get(Pcd.TokenSpaceGuidCName)\r
1423 if PcdGuidList:\r
1424 PcdList = PcdGuidList.get(Pcd.Type)\r
1425 if not PcdList:\r
1426 VPDPcdList.append(VPDPcdItem)\r
1427 for VpdPcd in PcdList:\r
1428 if PcdTokenCName == VpdPcd.TokenCName:\r
1429 break\r
1430 else:\r
1431 VPDPcdList.append(VPDPcdItem)\r
e651d06c 1432 if IsStructure:\r
a6a32677 1433 FiledOverrideFlag = False\r
85ccbee2 1434 OverrideValues = Pcd.SkuOverrideValues.get(Sku)\r
e651d06c 1435 if OverrideValues:\r
f8d11e5a 1436 Keys = list(OverrideValues.keys())\r
24326f38
YZ
1437 OverrideFieldStruct = self.OverrideFieldValue(Pcd, OverrideValues[Keys[0]])\r
1438 self.PrintStructureInfo(File, OverrideFieldStruct)\r
a6a32677
YZ
1439 FiledOverrideFlag = True\r
1440 if not FiledOverrideFlag and (Pcd.PcdFieldValueFromComm or Pcd.PcdFieldValueFromFdf):\r
1441 OverrideFieldStruct = self.OverrideFieldValue(Pcd, {})\r
1442 self.PrintStructureInfo(File, OverrideFieldStruct)\r
e651d06c
LG
1443 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)\r
1444\r
24326f38
YZ
1445 def OverrideFieldValue(self, Pcd, OverrideStruct):\r
1446 OverrideFieldStruct = collections.OrderedDict()\r
1447 if OverrideStruct:\r
82bfbd39
FB
1448 for _, Values in OverrideStruct.items():\r
1449 for Key,value in Values.items():\r
1450 if value[1] and value[1].endswith('.dsc'):\r
1451 OverrideFieldStruct[Key] = value\r
543f5ac3
B
1452 if Pcd.PcdFieldValueFromFdf:\r
1453 for Key, Values in Pcd.PcdFieldValueFromFdf.items():\r
39f0156f
YF
1454 if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:\r
1455 continue\r
543f5ac3 1456 OverrideFieldStruct[Key] = Values\r
24326f38
YZ
1457 if Pcd.PcdFieldValueFromComm:\r
1458 for Key, Values in Pcd.PcdFieldValueFromComm.items():\r
39f0156f
YF
1459 if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:\r
1460 continue\r
24326f38
YZ
1461 OverrideFieldStruct[Key] = Values\r
1462 return OverrideFieldStruct\r
1463\r
e651d06c 1464 def PrintStructureInfo(self, File, Struct):\r
39f0156f 1465 for Key, Value in sorted(Struct.items(), key=lambda x: x[0]):\r
f440f7e3
YZ
1466 if Value[1] and 'build command options' in Value[1]:\r
1467 FileWrite(File, ' *B %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))\r
39f0156f
YF
1468 elif Value[1] and Value[1].endswith('.fdf'):\r
1469 FileWrite(File, ' *F %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))\r
e651d06c 1470 else:\r
f440f7e3 1471 FileWrite(File, ' %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))\r
e651d06c
LG
1472\r
1473 def StrtoHex(self, value):\r
1474 try:\r
1475 value = hex(int(value))\r
1476 return value\r
1477 except:\r
1478 if value.startswith("L\"") and value.endswith("\""):\r
1479 valuelist = []\r
1480 for ch in value[2:-1]:\r
1481 valuelist.append(hex(ord(ch)))\r
1482 valuelist.append('0x00')\r
1483 return valuelist\r
1484 elif value.startswith("\"") and value.endswith("\""):\r
1485 return hex(ord(value[1:-1]))\r
1486 elif value.startswith("{") and value.endswith("}"):\r
1487 valuelist = []\r
1488 if ',' not in value:\r
1489 return value[1:-1]\r
1490 for ch in value[1:-1].split(','):\r
1491 ch = ch.strip()\r
1492 if ch.startswith('0x') or ch.startswith('0X'):\r
1493 valuelist.append(ch)\r
1494 continue\r
1495 try:\r
1496 valuelist.append(hex(int(ch.strip())))\r
1497 except:\r
1498 pass\r
1499 return valuelist\r
1500 else:\r
1501 return value\r
52302d4d 1502\r
0fd04efd
ZZ
1503 def IsStructurePcd(self, PcdToken, PcdTokenSpaceGuid):\r
1504 if GlobalData.gStructurePcd and (self.Arch in GlobalData.gStructurePcd) and ((PcdToken, PcdTokenSpaceGuid) in GlobalData.gStructurePcd[self.Arch]):\r
1505 return True\r
1506 else:\r
1507 return False\r
1508\r
52302d4d
LG
1509##\r
1510# Reports platform and module Prediction information\r
1511#\r
1512# This class reports the platform execution order prediction section and\r
1513# module load fixed address prediction subsection in the build report file.\r
1514#\r
1515class PredictionReport(object):\r
1516 ##\r
1517 # Constructor function for class PredictionReport\r
1518 #\r
1519 # This constructor function generates PredictionReport object for the platform.\r
1520 #\r
1521 # @param self: The object pointer\r
1522 # @param Wa Workspace context information\r
1523 #\r
1524 def __init__(self, Wa):\r
1525 self._MapFileName = os.path.join(Wa.BuildDir, Wa.Name + ".map")\r
1526 self._MapFileParsed = False\r
1527 self._EotToolInvoked = False\r
1528 self._FvDir = Wa.FvDir\r
1529 self._EotDir = Wa.BuildDir\r
1530 self._FfsEntryPoint = {}\r
1531 self._GuidMap = {}\r
1532 self._SourceList = []\r
1533 self.FixedMapDict = {}\r
1534 self.ItemList = []\r
1535 self.MaxLen = 0\r
1536\r
1537 #\r
1538 # Collect all platform reference source files and GUID C Name\r
1539 #\r
1540 for Pa in Wa.AutoGenObjectList:\r
1541 for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList:\r
1542 #\r
40d841f6
LG
1543 # BASE typed modules are EFI agnostic, so we need not scan\r
1544 # their source code to find PPI/Protocol produce or consume\r
1545 # information.\r
1546 #\r
8bb63e37 1547 if Module.ModuleType == SUP_MODULE_BASE:\r
40d841f6
LG
1548 continue\r
1549 #\r
52302d4d
LG
1550 # Add module referenced source files\r
1551 #\r
1552 self._SourceList.append(str(Module))\r
1553 IncludeList = {}\r
1554 for Source in Module.SourceFileList:\r
1555 if os.path.splitext(str(Source))[1].lower() == ".c":\r
1556 self._SourceList.append(" " + str(Source))\r
1557 FindIncludeFiles(Source.Path, Module.IncludePathList, IncludeList)\r
1558 for IncludeFile in IncludeList.values():\r
1559 self._SourceList.append(" " + IncludeFile)\r
1560\r
1561 for Guid in Module.PpiList:\r
1562 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.PpiList[Guid])\r
1563 for Guid in Module.ProtocolList:\r
1564 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.ProtocolList[Guid])\r
1565 for Guid in Module.GuidList:\r
1566 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.GuidList[Guid])\r
1567\r
1568 if Module.Guid and not Module.IsLibrary:\r
1569 EntryPoint = " ".join(Module.Module.ModuleEntryPointList)\r
82292501
FB
1570\r
1571 RealEntryPoint = "_ModuleEntryPoint"\r
52302d4d
LG
1572\r
1573 self._FfsEntryPoint[Module.Guid.upper()] = (EntryPoint, RealEntryPoint)\r
1574\r
1575\r
1576 #\r
1577 # Collect platform firmware volume list as the input of EOT.\r
1578 #\r
1579 self._FvList = []\r
1580 if Wa.FdfProfile:\r
1581 for Fd in Wa.FdfProfile.FdDict:\r
1582 for FdRegion in Wa.FdfProfile.FdDict[Fd].RegionList:\r
91fa33ee 1583 if FdRegion.RegionType != BINARY_FILE_TYPE_FV:\r
52302d4d
LG
1584 continue\r
1585 for FvName in FdRegion.RegionDataList:\r
1586 if FvName in self._FvList:\r
1587 continue\r
1588 self._FvList.append(FvName)\r
1589 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1590 for Section in Ffs.SectionList:\r
1591 try:\r
1592 for FvSection in Section.SectionList:\r
1593 if FvSection.FvName in self._FvList:\r
1594 continue\r
1595 self._FvList.append(FvSection.FvName)\r
1596 except AttributeError:\r
1597 pass\r
1598\r
1599\r
1600 ##\r
1601 # Parse platform fixed address map files\r
1602 #\r
1603 # This function parses the platform final fixed address map file to get\r
1604 # the database of predicted fixed address for module image base, entry point\r
1605 # etc.\r
1606 #\r
1607 # @param self: The object pointer\r
1608 #\r
1609 def _ParseMapFile(self):\r
1610 if self._MapFileParsed:\r
1611 return\r
1612 self._MapFileParsed = True\r
1613 if os.path.isfile(self._MapFileName):\r
1614 try:\r
1615 FileContents = open(self._MapFileName).read()\r
1616 for Match in gMapFileItemPattern.finditer(FileContents):\r
1617 AddressType = Match.group(1)\r
1618 BaseAddress = Match.group(2)\r
1619 EntryPoint = Match.group(3)\r
1620 Guid = Match.group(4).upper()\r
1621 List = self.FixedMapDict.setdefault(Guid, [])\r
1622 List.append((AddressType, BaseAddress, "*I"))\r
1623 List.append((AddressType, EntryPoint, "*E"))\r
1624 except:\r
1625 EdkLogger.warn(None, "Cannot open file to read", self._MapFileName)\r
1626\r
1627 ##\r
1628 # Invokes EOT tool to get the predicted the execution order.\r
1629 #\r
1630 # This function invokes EOT tool to calculate the predicted dispatch order\r
1631 #\r
1632 # @param self: The object pointer\r
1633 #\r
1634 def _InvokeEotTool(self):\r
1635 if self._EotToolInvoked:\r
1636 return\r
1637\r
1638 self._EotToolInvoked = True\r
1639 FvFileList = []\r
1640 for FvName in self._FvList:\r
1641 FvFile = os.path.join(self._FvDir, FvName + ".Fv")\r
1642 if os.path.isfile(FvFile):\r
1643 FvFileList.append(FvFile)\r
1644\r
1645 if len(FvFileList) == 0:\r
1646 return\r
1647 #\r
1648 # Write source file list and GUID file list to an intermediate file\r
1649 # as the input for EOT tool and dispatch List as the output file\r
1650 # from EOT tool.\r
1651 #\r
1652 SourceList = os.path.join(self._EotDir, "SourceFile.txt")\r
1653 GuidList = os.path.join(self._EotDir, "GuidList.txt")\r
1654 DispatchList = os.path.join(self._EotDir, "Dispatch.txt")\r
1655\r
c196d1d1 1656 TempFile = []\r
52302d4d
LG
1657 for Item in self._SourceList:\r
1658 FileWrite(TempFile, Item)\r
c196d1d1
FB
1659 SaveFileOnChange(SourceList, "".join(TempFile), False)\r
1660 TempFile = []\r
52302d4d
LG
1661 for Key in self._GuidMap:\r
1662 FileWrite(TempFile, "%s %s" % (Key, self._GuidMap[Key]))\r
c196d1d1 1663 SaveFileOnChange(GuidList, "".join(TempFile), False)\r
52302d4d
LG
1664\r
1665 try:\r
47f15da1 1666 from Eot.EotMain import Eot\r
40d841f6 1667\r
52302d4d 1668 #\r
40d841f6 1669 # Invoke EOT tool and echo its runtime performance\r
52302d4d 1670 #\r
40d841f6 1671 EotStartTime = time.time()\r
52302d4d
LG
1672 Eot(CommandLineOption=False, SourceFileList=SourceList, GuidList=GuidList,\r
1673 FvFileList=' '.join(FvFileList), Dispatch=DispatchList, IsInit=True)\r
40d841f6
LG
1674 EotEndTime = time.time()\r
1675 EotDuration = time.strftime("%H:%M:%S", time.gmtime(int(round(EotEndTime - EotStartTime))))\r
1676 EdkLogger.quiet("EOT run time: %s\n" % EotDuration)\r
f7496d71 1677\r
52302d4d
LG
1678 #\r
1679 # Parse the output of EOT tool\r
1680 #\r
1681 for Line in open(DispatchList):\r
1682 if len(Line.split()) < 4:\r
1683 continue\r
1684 (Guid, Phase, FfsName, FilePath) = Line.split()\r
1685 Symbol = self._FfsEntryPoint.get(Guid, [FfsName, ""])[0]\r
1686 if len(Symbol) > self.MaxLen:\r
1687 self.MaxLen = len(Symbol)\r
1688 self.ItemList.append((Phase, Symbol, FilePath))\r
1689 except:\r
1690 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))\r
1691 EdkLogger.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")\r
1692\r
1693\r
1694 ##\r
1695 # Generate platform execution order report\r
1696 #\r
1697 # This function generates the predicted module execution order.\r
1698 #\r
1699 # @param self The object pointer\r
1700 # @param File The file object for report\r
1701 #\r
1702 def _GenerateExecutionOrderReport(self, File):\r
1703 self._InvokeEotTool()\r
1704 if len(self.ItemList) == 0:\r
1705 return\r
1706 FileWrite(File, gSectionStart)\r
1707 FileWrite(File, "Execution Order Prediction")\r
1708 FileWrite(File, "*P PEI phase")\r
1709 FileWrite(File, "*D DXE phase")\r
1710 FileWrite(File, "*E Module INF entry point name")\r
1711 FileWrite(File, "*N Module notification function name")\r
1712\r
1713 FileWrite(File, "Type %-*s %s" % (self.MaxLen, "Symbol", "Module INF Path"))\r
1714 FileWrite(File, gSectionSep)\r
1715 for Item in self.ItemList:\r
1716 FileWrite(File, "*%sE %-*s %s" % (Item[0], self.MaxLen, Item[1], Item[2]))\r
1717\r
1718 FileWrite(File, gSectionStart)\r
1719\r
1720 ##\r
1721 # Generate Fixed Address report.\r
1722 #\r
1723 # This function generate the predicted fixed address report for a module\r
1724 # specified by Guid.\r
1725 #\r
1726 # @param self The object pointer\r
1727 # @param File The file object for report\r
1728 # @param Guid The module Guid value.\r
1729 # @param NotifyList The list of all notify function in a module\r
1730 #\r
1731 def _GenerateFixedAddressReport(self, File, Guid, NotifyList):\r
1732 self._ParseMapFile()\r
1733 FixedAddressList = self.FixedMapDict.get(Guid)\r
1734 if not FixedAddressList:\r
1735 return\r
1736\r
1737 FileWrite(File, gSubSectionStart)\r
1738 FileWrite(File, "Fixed Address Prediction")\r
1739 FileWrite(File, "*I Image Loading Address")\r
1740 FileWrite(File, "*E Entry Point Address")\r
1741 FileWrite(File, "*N Notification Function Address")\r
1742 FileWrite(File, "*F Flash Address")\r
1743 FileWrite(File, "*M Memory Address")\r
1744 FileWrite(File, "*S SMM RAM Offset")\r
1745 FileWrite(File, "TOM Top of Memory")\r
1746\r
1747 FileWrite(File, "Type Address Name")\r
1748 FileWrite(File, gSubSectionSep)\r
1749 for Item in FixedAddressList:\r
1750 Type = Item[0]\r
1751 Value = Item[1]\r
1752 Symbol = Item[2]\r
1753 if Symbol == "*I":\r
1754 Name = "(Image Base)"\r
1755 elif Symbol == "*E":\r
1756 Name = self._FfsEntryPoint.get(Guid, ["", "_ModuleEntryPoint"])[1]\r
1757 elif Symbol in NotifyList:\r
1758 Name = Symbol\r
1759 Symbol = "*N"\r
1760 else:\r
1761 continue\r
1762\r
1763 if "Flash" in Type:\r
1764 Symbol += "F"\r
1765 elif "Memory" in Type:\r
1766 Symbol += "M"\r
1767 else:\r
1768 Symbol += "S"\r
1769\r
1770 if Value[0] == "-":\r
1771 Value = "TOM" + Value\r
1772\r
1773 FileWrite(File, "%s %-16s %s" % (Symbol, Value, Name))\r
1774\r
1775 ##\r
1776 # Generate report for the prediction part\r
1777 #\r
1778 # This function generate the predicted fixed address report for a module or\r
1779 # predicted module execution order for a platform.\r
1780 # If the input Guid is None, then, it generates the predicted module execution order;\r
1781 # otherwise it generated the module fixed loading address for the module specified by\r
1782 # Guid.\r
1783 #\r
1784 # @param self The object pointer\r
1785 # @param File The file object for report\r
1786 # @param Guid The module Guid value.\r
1787 #\r
1788 def GenerateReport(self, File, Guid):\r
1789 if Guid:\r
1790 self._GenerateFixedAddressReport(File, Guid.upper(), [])\r
1791 else:\r
1792 self._GenerateExecutionOrderReport(File)\r
1793\r
1794##\r
1795# Reports FD region information\r
1796#\r
1797# This class reports the FD subsection in the build report file.\r
1798# It collects region information of platform flash device.\r
1799# If the region is a firmware volume, it lists the set of modules\r
1800# and its space information; otherwise, it only lists its region name,\r
1801# base address and size in its sub-section header.\r
1802# If there are nesting FVs, the nested FVs will list immediate after\r
1803# this FD region subsection\r
1804#\r
1805class FdRegionReport(object):\r
1806 ##\r
1807 # Discover all the nested FV name list.\r
1808 #\r
1809 # This is an internal worker function to discover the all the nested FV information\r
1810 # in the parent firmware volume. It uses deep first search algorithm recursively to\r
1811 # find all the FV list name and append them to the list.\r
1812 #\r
1813 # @param self The object pointer\r
1814 # @param FvName The name of current firmware file system\r
1815 # @param Wa Workspace context information\r
1816 #\r
1817 def _DiscoverNestedFvList(self, FvName, Wa):\r
a2432972
EC
1818 FvDictKey=FvName.upper()\r
1819 if FvDictKey in Wa.FdfProfile.FvDict:\r
1820 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1821 for Section in Ffs.SectionList:\r
1822 try:\r
1823 for FvSection in Section.SectionList:\r
1824 if FvSection.FvName in self.FvList:\r
1825 continue\r
1826 self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName\r
1827 self.FvList.append(FvSection.FvName)\r
1828 self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0)\r
1829 self._DiscoverNestedFvList(FvSection.FvName, Wa)\r
1830 except AttributeError:\r
1831 pass\r
52302d4d
LG
1832\r
1833 ##\r
1834 # Constructor function for class FdRegionReport\r
1835 #\r
1836 # This constructor function generates FdRegionReport object for a specified FdRegion.\r
1837 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware\r
1838 # volume list. This function also collects GUID map in order to dump module identification\r
1839 # in the final report.\r
1840 #\r
1841 # @param self: The object pointer\r
1842 # @param FdRegion The current FdRegion object\r
1843 # @param Wa Workspace context information\r
1844 #\r
1845 def __init__(self, FdRegion, Wa):\r
1846 self.Type = FdRegion.RegionType\r
1847 self.BaseAddress = FdRegion.Offset\r
1848 self.Size = FdRegion.Size\r
1849 self.FvList = []\r
1850 self.FvInfo = {}\r
1851 self._GuidsDb = {}\r
1852 self._FvDir = Wa.FvDir\r
aebe5a36 1853 self._WorkspaceDir = Wa.WorkspaceDir\r
52302d4d
LG
1854\r
1855 #\r
1856 # If the input FdRegion is not a firmware volume,\r
1857 # we are done.\r
1858 #\r
91fa33ee 1859 if self.Type != BINARY_FILE_TYPE_FV:\r
52302d4d
LG
1860 return\r
1861\r
1862 #\r
1863 # Find all nested FVs in the FdRegion\r
1864 #\r
1865 for FvName in FdRegion.RegionDataList:\r
1866 if FvName in self.FvList:\r
1867 continue\r
1868 self.FvList.append(FvName)\r
1869 self.FvInfo[FvName] = ("Fd Region", self.BaseAddress, self.Size)\r
1870 self._DiscoverNestedFvList(FvName, Wa)\r
1871\r
1872 PlatformPcds = {}\r
52302d4d
LG
1873 #\r
1874 # Collect PCDs declared in DEC files.\r
f7496d71 1875 #\r
0d2711a6
LG
1876 for Pa in Wa.AutoGenObjectList:\r
1877 for Package in Pa.PackageList:\r
1878 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
1879 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
1880 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue\r
52302d4d 1881 #\r
af9785a9 1882 # Collect PCDs defined in DSC file\r
52302d4d 1883 #\r
e651d06c
LG
1884 for Pa in Wa.AutoGenObjectList:\r
1885 for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:\r
1886 DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
af9785a9 1887 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
52302d4d
LG
1888\r
1889 #\r
1890 # Add PEI and DXE a priori files GUIDs defined in PI specification.\r
1891 #\r
9e47e6f9
CJ
1892 self._GuidsDb[PEI_APRIORI_GUID] = "PEI Apriori"\r
1893 self._GuidsDb[DXE_APRIORI_GUID] = "DXE Apriori"\r
52302d4d
LG
1894 #\r
1895 # Add ACPI table storage file\r
1896 #\r
1897 self._GuidsDb["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"\r
1898\r
1899 for Pa in Wa.AutoGenObjectList:\r
1900 for ModuleKey in Pa.Platform.Modules:\r
1901 M = Pa.Platform.Modules[ModuleKey].M\r
05cc51ad 1902 InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File)\r
52302d4d
LG
1903 self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath)\r
1904\r
1905 #\r
1906 # Collect the GUID map in the FV firmware volume\r
1907 #\r
1908 for FvName in self.FvList:\r
a2432972
EC
1909 FvDictKey=FvName.upper()\r
1910 if FvDictKey in Wa.FdfProfile.FvDict:\r
1911 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1912 try:\r
1913 #\r
1914 # collect GUID map for binary EFI file in FDF file.\r
1915 #\r
1916 Guid = Ffs.NameGuid.upper()\r
1917 Match = gPcdGuidPattern.match(Ffs.NameGuid)\r
1918 if Match:\r
1919 PcdTokenspace = Match.group(1)\r
1920 PcdToken = Match.group(2)\r
1921 if (PcdToken, PcdTokenspace) in PlatformPcds:\r
1922 GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)]\r
1923 Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()\r
1924 for Section in Ffs.SectionList:\r
1925 try:\r
1926 ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName)\r
1927 self._GuidsDb[Guid] = ModuleSectFile\r
1928 except AttributeError:\r
1929 pass\r
1930 except AttributeError:\r
1931 pass\r
52302d4d
LG
1932\r
1933\r
1934 ##\r
1935 # Internal worker function to generate report for the FD region\r
1936 #\r
1937 # This internal worker function to generate report for the FD region.\r
1938 # It the type is firmware volume, it lists offset and module identification.\r
1939 #\r
1940 # @param self The object pointer\r
1941 # @param File The file object for report\r
1942 # @param Title The title for the FD subsection\r
1943 # @param BaseAddress The base address for the FD region\r
1944 # @param Size The size of the FD region\r
1945 # @param FvName The FV name if the FD region is a firmware volume\r
1946 #\r
1947 def _GenerateReport(self, File, Title, Type, BaseAddress, Size=0, FvName=None):\r
1948 FileWrite(File, gSubSectionStart)\r
1949 FileWrite(File, Title)\r
1950 FileWrite(File, "Type: %s" % Type)\r
1951 FileWrite(File, "Base Address: 0x%X" % BaseAddress)\r
1952\r
91fa33ee 1953 if self.Type == BINARY_FILE_TYPE_FV:\r
52302d4d
LG
1954 FvTotalSize = 0\r
1955 FvTakenSize = 0\r
1956 FvFreeSize = 0\r
aebe5a36
YZ
1957 if FvName.upper().endswith('.FV'):\r
1958 FileExt = FvName + ".txt"\r
2157bc9c 1959 else:\r
aebe5a36
YZ
1960 FileExt = FvName + ".Fv.txt"\r
1961\r
1962 if not os.path.isfile(FileExt):\r
1963 FvReportFileName = mws.join(self._WorkspaceDir, FileExt)\r
1964 if not os.path.isfile(FvReportFileName):\r
1965 FvReportFileName = os.path.join(self._FvDir, FileExt)\r
52302d4d
LG
1966 try:\r
1967 #\r
1968 # Collect size info in the firmware volume.\r
1969 #\r
1970 FvReport = open(FvReportFileName).read()\r
1971 Match = gFvTotalSizePattern.search(FvReport)\r
1972 if Match:\r
1973 FvTotalSize = int(Match.group(1), 16)\r
1974 Match = gFvTakenSizePattern.search(FvReport)\r
1975 if Match:\r
1976 FvTakenSize = int(Match.group(1), 16)\r
1977 FvFreeSize = FvTotalSize - FvTakenSize\r
1978 #\r
1979 # Write size information to the report file.\r
1980 #\r
1981 FileWrite(File, "Size: 0x%X (%.0fK)" % (FvTotalSize, FvTotalSize / 1024.0))\r
1982 FileWrite(File, "Fv Name: %s (%.1f%% Full)" % (FvName, FvTakenSize * 100.0 / FvTotalSize))\r
1983 FileWrite(File, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize, FvTakenSize / 1024.0))\r
1984 FileWrite(File, "Free Size: 0x%X (%.0fK)" % (FvFreeSize, FvFreeSize / 1024.0))\r
1985 FileWrite(File, "Offset Module")\r
1986 FileWrite(File, gSubSectionSep)\r
1987 #\r
1988 # Write module offset and module identification to the report file.\r
1989 #\r
1990 OffsetInfo = {}\r
1991 for Match in gOffsetGuidPattern.finditer(FvReport):\r
1992 Guid = Match.group(2).upper()\r
1993 OffsetInfo[Match.group(1)] = self._GuidsDb.get(Guid, Guid)\r
0d1f5b2b 1994 OffsetList = sorted(OffsetInfo.keys())\r
52302d4d
LG
1995 for Offset in OffsetList:\r
1996 FileWrite (File, "%s %s" % (Offset, OffsetInfo[Offset]))\r
1997 except IOError:\r
1998 EdkLogger.warn(None, "Fail to read report file", FvReportFileName)\r
1999 else:\r
2000 FileWrite(File, "Size: 0x%X (%.0fK)" % (Size, Size / 1024.0))\r
2001 FileWrite(File, gSubSectionEnd)\r
2002\r
2003 ##\r
2004 # Generate report for the FD region\r
2005 #\r
2006 # This function generates report for the FD region.\r
2007 #\r
2008 # @param self The object pointer\r
2009 # @param File The file object for report\r
2010 #\r
2011 def GenerateReport(self, File):\r
2012 if (len(self.FvList) > 0):\r
2013 for FvItem in self.FvList:\r
2014 Info = self.FvInfo[FvItem]\r
91fa33ee 2015 self._GenerateReport(File, Info[0], TAB_FV_DIRECTORY, Info[1], Info[2], FvItem)\r
52302d4d
LG
2016 else:\r
2017 self._GenerateReport(File, "FD Region", self.Type, self.BaseAddress, self.Size)\r
2018\r
2019##\r
2020# Reports FD information\r
2021#\r
2022# This class reports the FD section in the build report file.\r
2023# It collects flash device information for a platform.\r
2024#\r
2025class FdReport(object):\r
2026 ##\r
2027 # Constructor function for class FdReport\r
2028 #\r
2029 # This constructor function generates FdReport object for a specified\r
2030 # firmware device.\r
2031 #\r
2032 # @param self The object pointer\r
2033 # @param Fd The current Firmware device object\r
2034 # @param Wa Workspace context information\r
2035 #\r
2036 def __init__(self, Fd, Wa):\r
2037 self.FdName = Fd.FdUiName\r
2038 self.BaseAddress = Fd.BaseAddress\r
2039 self.Size = Fd.Size\r
2040 self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList]\r
91fa33ee 2041 self.FvPath = os.path.join(Wa.BuildDir, TAB_FV_DIRECTORY)\r
043928da
YZ
2042 self.VPDBaseAddress = 0\r
2043 self.VPDSize = 0\r
fb3d2279 2044 for index, FdRegion in enumerate(Fd.RegionList):\r
ec97412b 2045 if str(FdRegion.RegionType) == 'FILE' and Wa.Platform.VpdToolGuid in str(FdRegion.RegionDataList):\r
fb3d2279
YZ
2046 self.VPDBaseAddress = self.FdRegionList[index].BaseAddress\r
2047 self.VPDSize = self.FdRegionList[index].Size\r
2048 break\r
2049\r
52302d4d
LG
2050 ##\r
2051 # Generate report for the firmware device.\r
2052 #\r
2053 # This function generates report for the firmware device.\r
2054 #\r
2055 # @param self The object pointer\r
2056 # @param File The file object for report\r
2057 #\r
2058 def GenerateReport(self, File):\r
2059 FileWrite(File, gSectionStart)\r
2060 FileWrite(File, "Firmware Device (FD)")\r
2061 FileWrite(File, "FD Name: %s" % self.FdName)\r
2062 FileWrite(File, "Base Address: %s" % self.BaseAddress)\r
2063 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.Size, self.Size / 1024.0))\r
2064 if len(self.FdRegionList) > 0:\r
2065 FileWrite(File, gSectionSep)\r
2066 for FdRegionItem in self.FdRegionList:\r
2067 FdRegionItem.GenerateReport(File)\r
2068\r
ebed920f
YZ
2069 if VPDPcdList:\r
2070 VPDPcdList.sort(key=lambda x: int(x[2], 0))\r
fb3d2279
YZ
2071 FileWrite(File, gSubSectionStart)\r
2072 FileWrite(File, "FD VPD Region")\r
2073 FileWrite(File, "Base Address: 0x%X" % self.VPDBaseAddress)\r
2074 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.VPDSize, self.VPDSize / 1024.0))\r
2075 FileWrite(File, gSubSectionSep)\r
ebed920f
YZ
2076 for item in VPDPcdList:\r
2077 # Add BaseAddress for offset\r
2078 Offset = '0x%08X' % (int(item[2], 16) + self.VPDBaseAddress)\r
2079 IsByteArray, ArrayList = ByteArrayForamt(item[-1])\r
2080 Skuinfo = item[1]\r
2081 if len(GlobalData.gSkuids) == 1 :\r
2082 Skuinfo = GlobalData.gSkuids[0]\r
e651d06c 2083 if IsByteArray:\r
ebed920f 2084 FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], '{'))\r
e651d06c 2085 for Array in ArrayList:\r
caf74495 2086 FileWrite(File, Array)\r
e651d06c 2087 else:\r
ebed920f 2088 FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], item[-1]))\r
fb3d2279 2089 FileWrite(File, gSubSectionEnd)\r
52302d4d
LG
2090 FileWrite(File, gSectionEnd)\r
2091\r
2092\r
2093\r
2094##\r
2095# Reports platform information\r
2096#\r
2097# This class reports the whole platform information\r
2098#\r
2099class PlatformReport(object):\r
2100 ##\r
2101 # Constructor function for class PlatformReport\r
2102 #\r
2103 # This constructor function generates PlatformReport object a platform build.\r
2104 # It generates report for platform summary, flash, global PCDs and detailed\r
2105 # module information for modules involved in platform build.\r
2106 #\r
2107 # @param self The object pointer\r
2108 # @param Wa Workspace context information\r
d5d56f1b 2109 # @param MaList The list of modules in the platform build\r
52302d4d 2110 #\r
d5d56f1b 2111 def __init__(self, Wa, MaList, ReportType):\r
52302d4d
LG
2112 self._WorkspaceDir = Wa.WorkspaceDir\r
2113 self.PlatformName = Wa.Name\r
2114 self.PlatformDscPath = Wa.Platform\r
2115 self.Architectures = " ".join(Wa.ArchList)\r
2116 self.ToolChain = Wa.ToolChain\r
2117 self.Target = Wa.BuildTarget\r
2118 self.OutputPath = os.path.join(Wa.WorkspaceDir, Wa.OutputDir)\r
2119 self.BuildEnvironment = platform.platform()\r
2120\r
2121 self.PcdReport = None\r
2122 if "PCD" in ReportType:\r
2123 self.PcdReport = PcdReport(Wa)\r
2124\r
2125 self.FdReportList = []\r
4231a819 2126 if "FLASH" in ReportType and Wa.FdfProfile and MaList is None:\r
52302d4d
LG
2127 for Fd in Wa.FdfProfile.FdDict:\r
2128 self.FdReportList.append(FdReport(Wa.FdfProfile.FdDict[Fd], Wa))\r
2129\r
2130 self.PredictionReport = None\r
2131 if "FIXED_ADDRESS" in ReportType or "EXECUTION_ORDER" in ReportType:\r
2132 self.PredictionReport = PredictionReport(Wa)\r
2133\r
e56468c0 2134 self.DepexParser = None\r
2135 if "DEPEX" in ReportType:\r
2136 self.DepexParser = DepexParser(Wa)\r
f7496d71 2137\r
52302d4d 2138 self.ModuleReportList = []\r
4231a819 2139 if MaList is not None:\r
636f2be6 2140 self._IsModuleBuild = True\r
d5d56f1b
LG
2141 for Ma in MaList:\r
2142 self.ModuleReportList.append(ModuleReport(Ma, ReportType))\r
2143 else:\r
636f2be6 2144 self._IsModuleBuild = False\r
d5d56f1b 2145 for Pa in Wa.AutoGenObjectList:\r
25193a33 2146 ModuleAutoGenList = []\r
d5d56f1b 2147 for ModuleKey in Pa.Platform.Modules:\r
25193a33 2148 ModuleAutoGenList.append(Pa.Platform.Modules[ModuleKey].M)\r
4231a819 2149 if GlobalData.gFdfParser is not None:\r
25193a33
YZ
2150 if Pa.Arch in GlobalData.gFdfParser.Profile.InfDict:\r
2151 INFList = GlobalData.gFdfParser.Profile.InfDict[Pa.Arch]\r
2152 for InfName in INFList:\r
2153 InfClass = PathClass(NormPath(InfName), Wa.WorkspaceDir, Pa.Arch)\r
0970a805 2154 Ma = ModuleAutoGen(Wa, InfClass, Pa.BuildTarget, Pa.ToolChain, Pa.Arch, Wa.MetaFile, Pa.DataPipe)\r
4231a819 2155 if Ma is None:\r
25193a33
YZ
2156 continue\r
2157 if Ma not in ModuleAutoGenList:\r
2158 ModuleAutoGenList.append(Ma)\r
2159 for MGen in ModuleAutoGenList:\r
2160 self.ModuleReportList.append(ModuleReport(MGen, ReportType))\r
52302d4d
LG
2161\r
2162\r
2163\r
2164 ##\r
2165 # Generate report for the whole platform.\r
2166 #\r
2167 # This function generates report for platform information.\r
2168 # It comprises of platform summary, global PCD, flash and\r
2169 # module list sections.\r
2170 #\r
2171 # @param self The object pointer\r
2172 # @param File The file object for report\r
2173 # @param BuildDuration The total time to build the modules\r
1b8eca8b
YZ
2174 # @param AutoGenTime The total time of AutoGen Phase\r
2175 # @param MakeTime The total time of Make Phase\r
2176 # @param GenFdsTime The total time of GenFds Phase\r
52302d4d
LG
2177 # @param ReportType The kind of report items in the final report file\r
2178 #\r
1b8eca8b 2179 def GenerateReport(self, File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, ReportType):\r
52302d4d
LG
2180 FileWrite(File, "Platform Summary")\r
2181 FileWrite(File, "Platform Name: %s" % self.PlatformName)\r
2182 FileWrite(File, "Platform DSC Path: %s" % self.PlatformDscPath)\r
2183 FileWrite(File, "Architectures: %s" % self.Architectures)\r
2184 FileWrite(File, "Tool Chain: %s" % self.ToolChain)\r
2185 FileWrite(File, "Target: %s" % self.Target)\r
e651d06c
LG
2186 if GlobalData.gSkuids:\r
2187 FileWrite(File, "SKUID: %s" % " ".join(GlobalData.gSkuids))\r
2188 if GlobalData.gDefaultStores:\r
2189 FileWrite(File, "DefaultStore: %s" % " ".join(GlobalData.gDefaultStores))\r
52302d4d
LG
2190 FileWrite(File, "Output Path: %s" % self.OutputPath)\r
2191 FileWrite(File, "Build Environment: %s" % self.BuildEnvironment)\r
2192 FileWrite(File, "Build Duration: %s" % BuildDuration)\r
1b8eca8b
YZ
2193 if AutoGenTime:\r
2194 FileWrite(File, "AutoGen Duration: %s" % AutoGenTime)\r
2195 if MakeTime:\r
2196 FileWrite(File, "Make Duration: %s" % MakeTime)\r
2197 if GenFdsTime:\r
2198 FileWrite(File, "GenFds Duration: %s" % GenFdsTime)\r
52302d4d
LG
2199 FileWrite(File, "Report Content: %s" % ", ".join(ReportType))\r
2200\r
2a29017e
YZ
2201 if GlobalData.MixedPcd:\r
2202 FileWrite(File, gSectionStart)\r
2203 FileWrite(File, "The following PCDs use different access methods:")\r
2204 FileWrite(File, gSectionSep)\r
2205 for PcdItem in GlobalData.MixedPcd:\r
2206 FileWrite(File, "%s.%s" % (str(PcdItem[1]), str(PcdItem[0])))\r
2207 FileWrite(File, gSectionEnd)\r
2208\r
636f2be6
LG
2209 if not self._IsModuleBuild:\r
2210 if "PCD" in ReportType:\r
2211 self.PcdReport.GenerateReport(File, None)\r
f7496d71 2212\r
636f2be6
LG
2213 if "FLASH" in ReportType:\r
2214 for FdReportListItem in self.FdReportList:\r
2215 FdReportListItem.GenerateReport(File)\r
52302d4d
LG
2216\r
2217 for ModuleReportItem in self.ModuleReportList:\r
e56468c0 2218 ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, self.DepexParser, ReportType)\r
52302d4d 2219\r
636f2be6
LG
2220 if not self._IsModuleBuild:\r
2221 if "EXECUTION_ORDER" in ReportType:\r
2222 self.PredictionReport.GenerateReport(File, None)\r
52302d4d
LG
2223\r
2224## BuildReport class\r
2225#\r
2226# This base class contain the routines to collect data and then\r
2227# applies certain format to the output report\r
2228#\r
2229class BuildReport(object):\r
2230 ##\r
2231 # Constructor function for class BuildReport\r
2232 #\r
2233 # This constructor function generates BuildReport object a platform build.\r
2234 # It generates report for platform summary, flash, global PCDs and detailed\r
2235 # module information for modules involved in platform build.\r
2236 #\r
2237 # @param self The object pointer\r
2238 # @param ReportFile The file name to save report file\r
2239 # @param ReportType The kind of report items in the final report file\r
2240 #\r
2241 def __init__(self, ReportFile, ReportType):\r
2242 self.ReportFile = ReportFile\r
2243 if ReportFile:\r
2244 self.ReportList = []\r
2245 self.ReportType = []\r
f7496d71 2246 if ReportType:\r
52302d4d
LG
2247 for ReportTypeItem in ReportType:\r
2248 if ReportTypeItem not in self.ReportType:\r
2249 self.ReportType.append(ReportTypeItem)\r
2250 else:\r
eca5be7a 2251 self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]\r
52302d4d
LG
2252 ##\r
2253 # Adds platform report to the list\r
2254 #\r
2255 # This function adds a platform report to the final report list.\r
2256 #\r
2257 # @param self The object pointer\r
2258 # @param Wa Workspace context information\r
d5d56f1b 2259 # @param MaList The list of modules in the platform build\r
52302d4d 2260 #\r
d5d56f1b 2261 def AddPlatformReport(self, Wa, MaList=None):\r
52302d4d 2262 if self.ReportFile:\r
d5d56f1b 2263 self.ReportList.append((Wa, MaList))\r
52302d4d
LG
2264\r
2265 ##\r
2266 # Generates the final report.\r
2267 #\r
2268 # This function generates platform build report. It invokes GenerateReport()\r
2269 # method for every platform report in the list.\r
2270 #\r
2271 # @param self The object pointer\r
2272 # @param BuildDuration The total time to build the modules\r
1b8eca8b
YZ
2273 # @param AutoGenTime The total time of AutoGen phase\r
2274 # @param MakeTime The total time of Make phase\r
2275 # @param GenFdsTime The total time of GenFds phase\r
52302d4d 2276 #\r
1b8eca8b 2277 def GenerateReport(self, BuildDuration, AutoGenTime, MakeTime, GenFdsTime):\r
52302d4d
LG
2278 if self.ReportFile:\r
2279 try:\r
d943b0c3 2280 File = []\r
d5d56f1b 2281 for (Wa, MaList) in self.ReportList:\r
1b8eca8b 2282 PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, self.ReportType)\r
d943b0c3
FB
2283 Content = FileLinesSplit(''.join(File), gLineMaxLength)\r
2284 SaveFileOnChange(self.ReportFile, Content, False)\r
40d841f6 2285 EdkLogger.quiet("Build report can be found at %s" % os.path.abspath(self.ReportFile))\r
52302d4d
LG
2286 except IOError:\r
2287 EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)\r
2288 except:\r
2289 EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report", ExtraData=self.ReportFile, RaiseError=False)\r
2290 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))\r
f7496d71 2291\r
52302d4d
LG
2292# This acts like the main() function for the script, unless it is 'import'ed into another script.\r
2293if __name__ == '__main__':\r
2294 pass\r
2295\r