]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/BuildReport.py
BaseTools: Update report map file format
[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
8577d63c 63gModulePattern = r"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s,\s*Type=\w+\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"\r
52302d4d
LG
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
09af9bd9 699 GlobalPcdReport.GenerateReport(File, self.ModulePcdSet,self.FileGuid)\r
52302d4d
LG
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
09af9bd9 884 def GenerateReport(self, File, ModulePcdSet,ModuleGuid=None):\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
09af9bd9 900 self.GenerateReportDetail(File, ModulePcdSet,ModuleGuid = ModuleGuid)\r
c8d07c5e 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
09af9bd9 916 def GenerateReportDetail(self, File, ModulePcdSet, ReportSubType = 0,ModuleGuid=None):\r
c8d07c5e
YZ
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
09af9bd9 996 PcdComponentValue = None\r
238d9b5c
YF
997 if ModulePcdSet is not None:\r
998 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type) not in ModulePcdSet:\r
999 continue\r
09af9bd9
BF
1000 InfDefaultValue, PcdComponentValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]\r
1001 PcdValue = PcdComponentValue\r
0fd04efd
ZZ
1002 #The DefaultValue of StructurePcd already be the latest, no need to update.\r
1003 if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):\r
1004 Pcd.DefaultValue = PcdValue\r
af246402
YF
1005 if InfDefaultValue:\r
1006 try:\r
1007 InfDefaultValue = ValueExpressionEx(InfDefaultValue, Pcd.DatumType, self._GuidDict)(True)\r
1008 except BadExpression as InfDefaultValue:\r
1009 EdkLogger.error('BuildReport', FORMAT_INVALID, "PCD Value: %s, Type: %s" % (InfDefaultValue, Pcd.DatumType))\r
5df16ecb
YF
1010 if InfDefaultValue == "":\r
1011 InfDefaultValue = None\r
238d9b5c
YF
1012\r
1013 BuildOptionMatch = False\r
1014 if GlobalData.BuildOptionPcd:\r
1015 for pcd in GlobalData.BuildOptionPcd:\r
1016 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) == (pcd[0], pcd[1]):\r
1017 if pcd[2]:\r
1018 continue\r
1019 PcdValue = pcd[3]\r
0fd04efd
ZZ
1020 #The DefaultValue of StructurePcd already be the latest, no need to update.\r
1021 if not self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):\r
1022 Pcd.DefaultValue = PcdValue\r
238d9b5c
YF
1023 BuildOptionMatch = True\r
1024 break\r
763e8edf 1025\r
238d9b5c
YF
1026 if First:\r
1027 if ModulePcdSet is None:\r
1028 FileWrite(File, "")\r
1029 FileWrite(File, Key)\r
1030 First = False\r
52302d4d
LG
1031\r
1032\r
7c41b813 1033 if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:\r
94c91295
ZF
1034 if PcdValue.startswith('0') and not PcdValue.lower().startswith('0x') and \\r
1035 len(PcdValue) > 1 and PcdValue.lstrip('0'):\r
1590d123 1036 PcdValue = PcdValue.lstrip('0')\r
1ccc4d89 1037 PcdValueNumber = int(PcdValue.strip(), 0)\r
238d9b5c
YF
1038 if DecDefaultValue is None:\r
1039 DecMatch = True\r
1040 else:\r
94c91295
ZF
1041 if DecDefaultValue.startswith('0') and not DecDefaultValue.lower().startswith('0x') and \\r
1042 len(DecDefaultValue) > 1 and DecDefaultValue.lstrip('0'):\r
1590d123 1043 DecDefaultValue = DecDefaultValue.lstrip('0')\r
238d9b5c
YF
1044 DecDefaultValueNumber = int(DecDefaultValue.strip(), 0)\r
1045 DecMatch = (DecDefaultValueNumber == PcdValueNumber)\r
52302d4d 1046\r
238d9b5c
YF
1047 if InfDefaultValue is None:\r
1048 InfMatch = True\r
1049 else:\r
94c91295
ZF
1050 if InfDefaultValue.startswith('0') and not InfDefaultValue.lower().startswith('0x') and \\r
1051 len(InfDefaultValue) > 1 and InfDefaultValue.lstrip('0'):\r
1590d123 1052 InfDefaultValue = InfDefaultValue.lstrip('0')\r
238d9b5c
YF
1053 InfDefaultValueNumber = int(InfDefaultValue.strip(), 0)\r
1054 InfMatch = (InfDefaultValueNumber == PcdValueNumber)\r
52302d4d 1055\r
238d9b5c
YF
1056 if DscDefaultValue is None:\r
1057 DscMatch = True\r
52302d4d 1058 else:\r
94c91295
ZF
1059 if DscDefaultValue.startswith('0') and not DscDefaultValue.lower().startswith('0x') and \\r
1060 len(DscDefaultValue) > 1 and DscDefaultValue.lstrip('0'):\r
1590d123 1061 DscDefaultValue = DscDefaultValue.lstrip('0')\r
1ccc4d89 1062 DscDefaultValueNumber = int(DscDefaultValue.strip(), 0)\r
238d9b5c
YF
1063 DscMatch = (DscDefaultValueNumber == PcdValueNumber)\r
1064 else:\r
1065 if DecDefaultValue is None:\r
1066 DecMatch = True\r
1067 else:\r
1068 DecMatch = (DecDefaultValue.strip() == PcdValue.strip())\r
52302d4d 1069\r
238d9b5c
YF
1070 if InfDefaultValue is None:\r
1071 InfMatch = True\r
1072 else:\r
1073 InfMatch = (InfDefaultValue.strip() == PcdValue.strip())\r
52302d4d 1074\r
238d9b5c
YF
1075 if DscDefaultValue is None:\r
1076 DscMatch = True\r
1077 else:\r
1078 DscMatch = (DscDefaultValue.strip() == PcdValue.strip())\r
1079\r
1080 IsStructure = False\r
0fd04efd 1081 if self.IsStructurePcd(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):\r
238d9b5c
YF
1082 IsStructure = True\r
1083 if TypeName in ('DYNVPD', 'DEXVPD'):\r
1084 SkuInfoList = Pcd.SkuInfoList\r
1085 Pcd = GlobalData.gStructurePcd[self.Arch][(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)]\r
09af9bd9
BF
1086 if ModulePcdSet and ModulePcdSet.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type)):\r
1087 InfDefaultValue, PcdComponentValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]\r
1088 DscDefaultValBak = Pcd.DefaultValue\r
1089 Pcd.DefaultValue = PcdComponentValue\r
1090\r
238d9b5c
YF
1091 Pcd.DatumType = Pcd.StructName\r
1092 if TypeName in ('DYNVPD', 'DEXVPD'):\r
1093 Pcd.SkuInfoList = SkuInfoList\r
a6a32677 1094 if Pcd.PcdValueFromComm or Pcd.PcdFieldValueFromComm:\r
238d9b5c
YF
1095 BuildOptionMatch = True\r
1096 DecMatch = False\r
a6a32677
YZ
1097 elif Pcd.PcdValueFromFdf or Pcd.PcdFieldValueFromFdf:\r
1098 DscDefaultValue = True\r
1099 DscMatch = True\r
1100 DecMatch = False\r
09af9bd9
BF
1101 else:\r
1102 if Pcd.Type in PCD_DYNAMIC_TYPE_SET | PCD_DYNAMIC_EX_TYPE_SET:\r
1103 DscOverride = False\r
1104 if Pcd.DefaultFromDSC:\r
1105 DscOverride = True\r
f8811378 1106 else:\r
09af9bd9
BF
1107 DictLen = 0\r
1108 for item in Pcd.SkuOverrideValues:\r
1109 DictLen += len(Pcd.SkuOverrideValues[item])\r
1110 if not DictLen:\r
1111 DscOverride = False\r
f8811378 1112 else:\r
09af9bd9
BF
1113 if not Pcd.SkuInfoList:\r
1114 OverrideValues = Pcd.SkuOverrideValues\r
1115 if OverrideValues:\r
1116 for Data in OverrideValues.values():\r
1117 Struct = list(Data.values())\r
1118 if Struct:\r
1119 DscOverride = self.ParseStruct(Struct[0])\r
5f094268 1120 break\r
09af9bd9
BF
1121 else:\r
1122 SkuList = sorted(Pcd.SkuInfoList.keys())\r
1123 for Sku in SkuList:\r
1124 SkuInfo = Pcd.SkuInfoList[Sku]\r
1125 if SkuInfo.DefaultStoreDict:\r
1126 DefaultStoreList = sorted(SkuInfo.DefaultStoreDict.keys())\r
1127 for DefaultStore in DefaultStoreList:\r
1128 OverrideValues = Pcd.SkuOverrideValues[Sku]\r
1129 DscOverride = self.ParseStruct(OverrideValues[DefaultStore])\r
1130 if DscOverride:\r
1131 break\r
1132 if DscOverride:\r
1133 break\r
1134 if DscOverride:\r
1135 DscDefaultValue = True\r
1136 DscMatch = True\r
1137 DecMatch = False\r
1138 else:\r
1139 DecMatch = True\r
f8811378 1140 else:\r
09af9bd9
BF
1141 if Pcd.DscRawValue or (ModuleGuid and ModuleGuid.replace("-","S") in Pcd.PcdValueFromComponents):\r
1142 DscDefaultValue = True\r
1143 DscMatch = True\r
1144 DecMatch = False\r
1145 else:\r
1146 DscDefaultValue = False\r
1147 DecMatch = True\r
238d9b5c
YF
1148\r
1149 #\r
1150 # Report PCD item according to their override relationship\r
1151 #\r
7c41b813 1152 if Pcd.DatumType == 'BOOLEAN':\r
1153 if DscDefaultValue:\r
1154 DscDefaultValue = str(int(DscDefaultValue, 0))\r
1155 if DecDefaultValue:\r
1156 DecDefaultValue = str(int(DecDefaultValue, 0))\r
1157 if InfDefaultValue:\r
1158 InfDefaultValue = str(int(InfDefaultValue, 0))\r
1159 if Pcd.DefaultValue:\r
1160 Pcd.DefaultValue = str(int(Pcd.DefaultValue, 0))\r
5df16ecb 1161 if DecMatch:\r
238d9b5c 1162 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, ' ')\r
5df16ecb
YF
1163 elif InfDefaultValue and InfMatch:\r
1164 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*M')\r
238d9b5c
YF
1165 elif BuildOptionMatch:\r
1166 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*B')\r
1167 else:\r
09af9bd9
BF
1168 if PcdComponentValue:\r
1169 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, PcdComponentValue, DecMatch, DecDefaultValue, '*M', ModuleGuid)\r
1170 elif DscDefaultValue and DscMatch:\r
5df16ecb 1171 if (Pcd.TokenCName, Key, Field) in self.FdfPcdSet:\r
238d9b5c 1172 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*F')\r
52302d4d 1173 else:\r
238d9b5c 1174 self.PrintPcdValue(File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValBak, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, '*P')\r
09af9bd9 1175\r
52302d4d 1176\r
238d9b5c
YF
1177 if ModulePcdSet is None:\r
1178 if IsStructure:\r
1179 continue\r
1180 if not TypeName in ('PATCH', 'FLAG', 'FIXED'):\r
1181 continue\r
1182 if not BuildOptionMatch:\r
1183 ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {})\r
1184 for ModulePath in ModuleOverride:\r
1185 ModuleDefault = ModuleOverride[ModulePath]\r
7c41b813 1186 if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:\r
94c91295
ZF
1187 if ModuleDefault.startswith('0') and not ModuleDefault.lower().startswith('0x') and \\r
1188 len(ModuleDefault) > 1 and ModuleDefault.lstrip('0'):\r
1590d123 1189 ModuleDefault = ModuleDefault.lstrip('0')\r
1ccc4d89 1190 ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)\r
238d9b5c 1191 Match = (ModulePcdDefaultValueNumber == PcdValueNumber)\r
7c41b813 1192 if Pcd.DatumType == 'BOOLEAN':\r
1193 ModuleDefault = str(ModulePcdDefaultValueNumber)\r
238d9b5c
YF
1194 else:\r
1195 Match = (ModuleDefault.strip() == PcdValue.strip())\r
1196 if Match:\r
1197 continue\r
1198 IsByteArray, ArrayList = ByteArrayForamt(ModuleDefault.strip())\r
1199 if IsByteArray:\r
1200 FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 15, ModulePath, '{'))\r
1201 for Array in ArrayList:\r
caf74495 1202 FileWrite(File, Array)\r
238d9b5c 1203 else:\r
cef7ecf6
YF
1204 Value = ModuleDefault.strip()\r
1205 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1206 if Value.startswith(('0x', '0X')):\r
1207 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1208 else:\r
1209 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
1210 FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 15, ModulePath, Value))\r
52302d4d 1211\r
4231a819 1212 if ModulePcdSet is None:\r
52302d4d
LG
1213 FileWrite(File, gSectionEnd)\r
1214 else:\r
c2d0a1f6 1215 if not ReportSubType and ModulePcdSet:\r
c8d07c5e 1216 FileWrite(File, gSubSectionEnd)\r
52302d4d 1217\r
24326f38
YZ
1218 def ParseStruct(self, struct):\r
1219 HasDscOverride = False\r
1220 if struct:\r
f8d11e5a 1221 for _, Values in list(struct.items()):\r
e3ef8f0c
FZ
1222 for Key, value in Values.items():\r
1223 if value[1] and value[1].endswith('.dsc'):\r
1224 HasDscOverride = True\r
1225 break\r
1226 if HasDscOverride == True:\r
24326f38
YZ
1227 break\r
1228 return HasDscOverride\r
52302d4d 1229\r
e651d06c 1230 def PrintPcdDefault(self, File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue):\r
4231a819 1231 if not DscMatch and DscDefaultValue is not None:\r
e651d06c
LG
1232 Value = DscDefaultValue.strip()\r
1233 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1234 if IsByteArray:\r
1235 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', "{"))\r
1236 for Array in ArrayList:\r
caf74495 1237 FileWrite(File, Array)\r
e651d06c 1238 else:\r
179c2f97
YF
1239 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1240 if Value.startswith(('0x', '0X')):\r
1241 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1242 else:\r
1243 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
e651d06c 1244 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', Value))\r
4231a819 1245 if not InfMatch and InfDefaultValue is not None:\r
e651d06c
LG
1246 Value = InfDefaultValue.strip()\r
1247 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1248 if IsByteArray:\r
1249 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', "{"))\r
1250 for Array in ArrayList:\r
caf74495 1251 FileWrite(File, Array)\r
e651d06c 1252 else:\r
179c2f97
YF
1253 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1254 if Value.startswith(('0x', '0X')):\r
1255 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1256 else:\r
1257 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
e651d06c
LG
1258 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', Value))\r
1259\r
4231a819 1260 if not DecMatch and DecDefaultValue is not None:\r
e651d06c
LG
1261 Value = DecDefaultValue.strip()\r
1262 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1263 if IsByteArray:\r
1264 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', "{"))\r
1265 for Array in ArrayList:\r
caf74495 1266 FileWrite(File, Array)\r
e651d06c 1267 else:\r
179c2f97
YF
1268 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1269 if Value.startswith(('0x', '0X')):\r
1270 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1271 else:\r
1ccc4d89 1272 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
e651d06c
LG
1273 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', Value))\r
1274 if IsStructure:\r
350c9ae0
FB
1275 for filedvalues in Pcd.DefaultValues.values():\r
1276 self.PrintStructureInfo(File, filedvalues)\r
24326f38 1277 if DecMatch and IsStructure:\r
350c9ae0
FB
1278 for filedvalues in Pcd.DefaultValues.values():\r
1279 self.PrintStructureInfo(File, filedvalues)\r
e651d06c 1280\r
09af9bd9 1281 def PrintPcdValue(self, File, Pcd, PcdTokenCName, TypeName, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue, Flag = ' ',ModuleGuid=None):\r
e651d06c
LG
1282 if not Pcd.SkuInfoList:\r
1283 Value = Pcd.DefaultValue\r
1284 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
1285 if IsByteArray:\r
1286 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '{'))\r
1287 for Array in ArrayList:\r
caf74495 1288 FileWrite(File, Array)\r
e651d06c 1289 else:\r
179c2f97 1290 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
94c91295 1291 if Value.startswith('0') and not Value.lower().startswith('0x') and len(Value) > 1 and Value.lstrip('0'):\r
1590d123 1292 Value = Value.lstrip('0')\r
ccaa7754 1293 if Value.startswith(('0x', '0X')):\r
179c2f97
YF
1294 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1295 else:\r
1296 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
e651d06c
LG
1297 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))\r
1298 if IsStructure:\r
a6a32677 1299 FiledOverrideFlag = False\r
8a64c7ea
FZ
1300 if (Pcd.TokenCName,Pcd.TokenSpaceGuidCName) in GlobalData.gPcdSkuOverrides:\r
1301 OverrideValues = GlobalData.gPcdSkuOverrides[(Pcd.TokenCName,Pcd.TokenSpaceGuidCName)]\r
1302 else:\r
1303 OverrideValues = Pcd.SkuOverrideValues\r
09af9bd9 1304 FieldOverrideValues = None\r
e651d06c 1305 if OverrideValues:\r
2c65efac
YZ
1306 for Data in OverrideValues.values():\r
1307 Struct = list(Data.values())\r
1308 if Struct:\r
09af9bd9 1309 FieldOverrideValues = Struct[0]\r
a6a32677 1310 FiledOverrideFlag = True\r
2c65efac 1311 break\r
09af9bd9
BF
1312 if Pcd.PcdFiledValueFromDscComponent and ModuleGuid and ModuleGuid.replace("-","S") in Pcd.PcdFiledValueFromDscComponent:\r
1313 FieldOverrideValues = Pcd.PcdFiledValueFromDscComponent[ModuleGuid.replace("-","S")]\r
1314 if FieldOverrideValues:\r
1315 OverrideFieldStruct = self.OverrideFieldValue(Pcd, FieldOverrideValues)\r
1316 self.PrintStructureInfo(File, OverrideFieldStruct)\r
1317\r
a6a32677
YZ
1318 if not FiledOverrideFlag and (Pcd.PcdFieldValueFromComm or Pcd.PcdFieldValueFromFdf):\r
1319 OverrideFieldStruct = self.OverrideFieldValue(Pcd, {})\r
1320 self.PrintStructureInfo(File, OverrideFieldStruct)\r
e651d06c
LG
1321 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)\r
1322 else:\r
1323 FirstPrint = True\r
1324 SkuList = sorted(Pcd.SkuInfoList.keys())\r
1325 for Sku in SkuList:\r
1326 SkuInfo = Pcd.SkuInfoList[Sku]\r
779ddcdf 1327 SkuIdName = SkuInfo.SkuIdName\r
e651d06c
LG
1328 if TypeName in ('DYNHII', 'DEXHII'):\r
1329 if SkuInfo.DefaultStoreDict:\r
1330 DefaultStoreList = sorted(SkuInfo.DefaultStoreDict.keys())\r
1331 for DefaultStore in DefaultStoreList:\r
1332 Value = SkuInfo.DefaultStoreDict[DefaultStore]\r
1333 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
7c41b813 1334 if Pcd.DatumType == 'BOOLEAN':\r
1335 Value = str(int(Value, 0))\r
e651d06c
LG
1336 if FirstPrint:\r
1337 FirstPrint = False\r
1338 if IsByteArray:\r
779ddcdf
YZ
1339 if self.DefaultStoreSingle and self.SkuSingle:\r
1340 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '{'))\r
1341 elif self.DefaultStoreSingle and not self.SkuSingle:\r
1342 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '{'))\r
1343 elif not self.DefaultStoreSingle and self.SkuSingle:\r
1344 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', '{'))\r
1345 else:\r
1346 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', '{'))\r
e651d06c 1347 for Array in ArrayList:\r
caf74495 1348 FileWrite(File, Array)\r
e651d06c 1349 else:\r
179c2f97
YF
1350 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1351 if Value.startswith(('0x', '0X')):\r
1352 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1353 else:\r
1354 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
779ddcdf
YZ
1355 if self.DefaultStoreSingle and self.SkuSingle:\r
1356 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))\r
1357 elif self.DefaultStoreSingle and not self.SkuSingle:\r
1358 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))\r
1359 elif not self.DefaultStoreSingle and self.SkuSingle:\r
1360 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', Value))\r
1361 else:\r
1362 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', Value))\r
e651d06c
LG
1363 else:\r
1364 if IsByteArray:\r
779ddcdf
YZ
1365 if self.DefaultStoreSingle and self.SkuSingle:\r
1366 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '{'))\r
1367 elif self.DefaultStoreSingle and not self.SkuSingle:\r
1368 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '{'))\r
1369 elif not self.DefaultStoreSingle and self.SkuSingle:\r
1370 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', '{'))\r
1371 else:\r
1372 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', '{'))\r
e651d06c 1373 for Array in ArrayList:\r
caf74495 1374 FileWrite(File, Array)\r
e651d06c 1375 else:\r
179c2f97
YF
1376 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1377 if Value.startswith(('0x', '0X')):\r
1378 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1379 else:\r
1380 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
779ddcdf
YZ
1381 if self.DefaultStoreSingle and self.SkuSingle:\r
1382 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', Value))\r
1383 elif self.DefaultStoreSingle and not self.SkuSingle:\r
1384 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))\r
1385 elif not self.DefaultStoreSingle and self.SkuSingle:\r
1386 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + DefaultStore + ')', Value))\r
1387 else:\r
1388 FileWrite(File, ' %-*s : %6s %10s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', '(' + DefaultStore + ')', Value))\r
e651d06c
LG
1389 FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset))\r
1390 if IsStructure:\r
65eff519 1391 OverrideValues = Pcd.SkuOverrideValues[Sku]\r
24326f38
YZ
1392 OverrideFieldStruct = self.OverrideFieldValue(Pcd, OverrideValues[DefaultStore])\r
1393 self.PrintStructureInfo(File, OverrideFieldStruct)\r
e651d06c 1394 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)\r
e651d06c
LG
1395 else:\r
1396 Value = SkuInfo.DefaultValue\r
1397 IsByteArray, ArrayList = ByteArrayForamt(Value)\r
7c41b813 1398 if Pcd.DatumType == 'BOOLEAN':\r
1399 Value = str(int(Value, 0))\r
e651d06c
LG
1400 if FirstPrint:\r
1401 FirstPrint = False\r
1402 if IsByteArray:\r
779ddcdf
YZ
1403 if self.SkuSingle:\r
1404 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', "{"))\r
1405 else:\r
1406 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', "{"))\r
e651d06c 1407 for Array in ArrayList:\r
caf74495 1408 FileWrite(File, Array)\r
e651d06c 1409 else:\r
179c2f97
YF
1410 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1411 if Value.startswith(('0x', '0X')):\r
1412 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1413 else:\r
1414 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
779ddcdf
YZ
1415 if self.SkuSingle:\r
1416 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', Value))\r
1417 else:\r
1418 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, Flag + ' ' + PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))\r
e651d06c
LG
1419 else:\r
1420 if IsByteArray:\r
779ddcdf 1421 if self.SkuSingle:\r
ccaa7754 1422 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', "{"))\r
779ddcdf 1423 else:\r
ccaa7754 1424 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', "{"))\r
e651d06c 1425 for Array in ArrayList:\r
caf74495 1426 FileWrite(File, Array)\r
e651d06c 1427 else:\r
179c2f97
YF
1428 if Pcd.DatumType in TAB_PCD_CLEAN_NUMERIC_TYPES:\r
1429 if Value.startswith(('0x', '0X')):\r
1430 Value = '{} ({:d})'.format(Value, int(Value, 0))\r
1431 else:\r
1432 Value = "0x{:X} ({})".format(int(Value, 0), Value)\r
779ddcdf 1433 if self.SkuSingle:\r
ccaa7754 1434 FileWrite(File, ' %-*s : %6s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', Value))\r
779ddcdf 1435 else:\r
ccaa7754 1436 FileWrite(File, ' %-*s : %6s %10s %10s = %s' % (self.MaxLen, ' ', TypeName, '(' + Pcd.DatumType + ')', '(' + SkuIdName + ')', Value))\r
779ddcdf
YZ
1437 if TypeName in ('DYNVPD', 'DEXVPD'):\r
1438 FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset))\r
ebed920f
YZ
1439 VPDPcdItem = (Pcd.TokenSpaceGuidCName + '.' + PcdTokenCName, SkuIdName, SkuInfo.VpdOffset, Pcd.MaxDatumSize, SkuInfo.DefaultValue)\r
1440 if VPDPcdItem not in VPDPcdList:\r
85ccbee2
FZ
1441 PcdGuidList = self.UnusedPcds.get(Pcd.TokenSpaceGuidCName)\r
1442 if PcdGuidList:\r
1443 PcdList = PcdGuidList.get(Pcd.Type)\r
1444 if not PcdList:\r
1445 VPDPcdList.append(VPDPcdItem)\r
1446 for VpdPcd in PcdList:\r
1447 if PcdTokenCName == VpdPcd.TokenCName:\r
1448 break\r
1449 else:\r
1450 VPDPcdList.append(VPDPcdItem)\r
e651d06c 1451 if IsStructure:\r
a6a32677 1452 FiledOverrideFlag = False\r
85ccbee2 1453 OverrideValues = Pcd.SkuOverrideValues.get(Sku)\r
e651d06c 1454 if OverrideValues:\r
f8d11e5a 1455 Keys = list(OverrideValues.keys())\r
24326f38
YZ
1456 OverrideFieldStruct = self.OverrideFieldValue(Pcd, OverrideValues[Keys[0]])\r
1457 self.PrintStructureInfo(File, OverrideFieldStruct)\r
a6a32677
YZ
1458 FiledOverrideFlag = True\r
1459 if not FiledOverrideFlag and (Pcd.PcdFieldValueFromComm or Pcd.PcdFieldValueFromFdf):\r
1460 OverrideFieldStruct = self.OverrideFieldValue(Pcd, {})\r
1461 self.PrintStructureInfo(File, OverrideFieldStruct)\r
e651d06c
LG
1462 self.PrintPcdDefault(File, Pcd, IsStructure, DscMatch, DscDefaultValue, InfMatch, InfDefaultValue, DecMatch, DecDefaultValue)\r
1463\r
24326f38
YZ
1464 def OverrideFieldValue(self, Pcd, OverrideStruct):\r
1465 OverrideFieldStruct = collections.OrderedDict()\r
1466 if OverrideStruct:\r
82bfbd39
FB
1467 for _, Values in OverrideStruct.items():\r
1468 for Key,value in Values.items():\r
1469 if value[1] and value[1].endswith('.dsc'):\r
1470 OverrideFieldStruct[Key] = value\r
543f5ac3
B
1471 if Pcd.PcdFieldValueFromFdf:\r
1472 for Key, Values in Pcd.PcdFieldValueFromFdf.items():\r
39f0156f
YF
1473 if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:\r
1474 continue\r
543f5ac3 1475 OverrideFieldStruct[Key] = Values\r
24326f38
YZ
1476 if Pcd.PcdFieldValueFromComm:\r
1477 for Key, Values in Pcd.PcdFieldValueFromComm.items():\r
39f0156f
YF
1478 if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:\r
1479 continue\r
24326f38
YZ
1480 OverrideFieldStruct[Key] = Values\r
1481 return OverrideFieldStruct\r
1482\r
e651d06c 1483 def PrintStructureInfo(self, File, Struct):\r
39f0156f 1484 for Key, Value in sorted(Struct.items(), key=lambda x: x[0]):\r
f440f7e3
YZ
1485 if Value[1] and 'build command options' in Value[1]:\r
1486 FileWrite(File, ' *B %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))\r
39f0156f
YF
1487 elif Value[1] and Value[1].endswith('.fdf'):\r
1488 FileWrite(File, ' *F %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))\r
e651d06c 1489 else:\r
f440f7e3 1490 FileWrite(File, ' %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))\r
e651d06c
LG
1491\r
1492 def StrtoHex(self, value):\r
1493 try:\r
1494 value = hex(int(value))\r
1495 return value\r
1496 except:\r
1497 if value.startswith("L\"") and value.endswith("\""):\r
1498 valuelist = []\r
1499 for ch in value[2:-1]:\r
1500 valuelist.append(hex(ord(ch)))\r
1501 valuelist.append('0x00')\r
1502 return valuelist\r
1503 elif value.startswith("\"") and value.endswith("\""):\r
1504 return hex(ord(value[1:-1]))\r
1505 elif value.startswith("{") and value.endswith("}"):\r
1506 valuelist = []\r
1507 if ',' not in value:\r
1508 return value[1:-1]\r
1509 for ch in value[1:-1].split(','):\r
1510 ch = ch.strip()\r
1511 if ch.startswith('0x') or ch.startswith('0X'):\r
1512 valuelist.append(ch)\r
1513 continue\r
1514 try:\r
1515 valuelist.append(hex(int(ch.strip())))\r
1516 except:\r
1517 pass\r
1518 return valuelist\r
1519 else:\r
1520 return value\r
52302d4d 1521\r
0fd04efd
ZZ
1522 def IsStructurePcd(self, PcdToken, PcdTokenSpaceGuid):\r
1523 if GlobalData.gStructurePcd and (self.Arch in GlobalData.gStructurePcd) and ((PcdToken, PcdTokenSpaceGuid) in GlobalData.gStructurePcd[self.Arch]):\r
1524 return True\r
1525 else:\r
1526 return False\r
1527\r
52302d4d
LG
1528##\r
1529# Reports platform and module Prediction information\r
1530#\r
1531# This class reports the platform execution order prediction section and\r
1532# module load fixed address prediction subsection in the build report file.\r
1533#\r
1534class PredictionReport(object):\r
1535 ##\r
1536 # Constructor function for class PredictionReport\r
1537 #\r
1538 # This constructor function generates PredictionReport object for the platform.\r
1539 #\r
1540 # @param self: The object pointer\r
1541 # @param Wa Workspace context information\r
1542 #\r
1543 def __init__(self, Wa):\r
1544 self._MapFileName = os.path.join(Wa.BuildDir, Wa.Name + ".map")\r
1545 self._MapFileParsed = False\r
1546 self._EotToolInvoked = False\r
1547 self._FvDir = Wa.FvDir\r
1548 self._EotDir = Wa.BuildDir\r
1549 self._FfsEntryPoint = {}\r
1550 self._GuidMap = {}\r
1551 self._SourceList = []\r
1552 self.FixedMapDict = {}\r
1553 self.ItemList = []\r
1554 self.MaxLen = 0\r
1555\r
1556 #\r
1557 # Collect all platform reference source files and GUID C Name\r
1558 #\r
1559 for Pa in Wa.AutoGenObjectList:\r
1560 for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList:\r
1561 #\r
40d841f6
LG
1562 # BASE typed modules are EFI agnostic, so we need not scan\r
1563 # their source code to find PPI/Protocol produce or consume\r
1564 # information.\r
1565 #\r
8bb63e37 1566 if Module.ModuleType == SUP_MODULE_BASE:\r
40d841f6
LG
1567 continue\r
1568 #\r
52302d4d
LG
1569 # Add module referenced source files\r
1570 #\r
1571 self._SourceList.append(str(Module))\r
1572 IncludeList = {}\r
1573 for Source in Module.SourceFileList:\r
1574 if os.path.splitext(str(Source))[1].lower() == ".c":\r
1575 self._SourceList.append(" " + str(Source))\r
1576 FindIncludeFiles(Source.Path, Module.IncludePathList, IncludeList)\r
1577 for IncludeFile in IncludeList.values():\r
1578 self._SourceList.append(" " + IncludeFile)\r
1579\r
1580 for Guid in Module.PpiList:\r
1581 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.PpiList[Guid])\r
1582 for Guid in Module.ProtocolList:\r
1583 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.ProtocolList[Guid])\r
1584 for Guid in Module.GuidList:\r
1585 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.GuidList[Guid])\r
1586\r
1587 if Module.Guid and not Module.IsLibrary:\r
1588 EntryPoint = " ".join(Module.Module.ModuleEntryPointList)\r
82292501
FB
1589\r
1590 RealEntryPoint = "_ModuleEntryPoint"\r
52302d4d
LG
1591\r
1592 self._FfsEntryPoint[Module.Guid.upper()] = (EntryPoint, RealEntryPoint)\r
1593\r
1594\r
1595 #\r
1596 # Collect platform firmware volume list as the input of EOT.\r
1597 #\r
1598 self._FvList = []\r
1599 if Wa.FdfProfile:\r
1600 for Fd in Wa.FdfProfile.FdDict:\r
1601 for FdRegion in Wa.FdfProfile.FdDict[Fd].RegionList:\r
91fa33ee 1602 if FdRegion.RegionType != BINARY_FILE_TYPE_FV:\r
52302d4d
LG
1603 continue\r
1604 for FvName in FdRegion.RegionDataList:\r
1605 if FvName in self._FvList:\r
1606 continue\r
1607 self._FvList.append(FvName)\r
1608 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1609 for Section in Ffs.SectionList:\r
1610 try:\r
1611 for FvSection in Section.SectionList:\r
1612 if FvSection.FvName in self._FvList:\r
1613 continue\r
1614 self._FvList.append(FvSection.FvName)\r
1615 except AttributeError:\r
1616 pass\r
1617\r
1618\r
1619 ##\r
1620 # Parse platform fixed address map files\r
1621 #\r
1622 # This function parses the platform final fixed address map file to get\r
1623 # the database of predicted fixed address for module image base, entry point\r
1624 # etc.\r
1625 #\r
1626 # @param self: The object pointer\r
1627 #\r
1628 def _ParseMapFile(self):\r
1629 if self._MapFileParsed:\r
1630 return\r
1631 self._MapFileParsed = True\r
1632 if os.path.isfile(self._MapFileName):\r
1633 try:\r
1634 FileContents = open(self._MapFileName).read()\r
1635 for Match in gMapFileItemPattern.finditer(FileContents):\r
1636 AddressType = Match.group(1)\r
1637 BaseAddress = Match.group(2)\r
1638 EntryPoint = Match.group(3)\r
1639 Guid = Match.group(4).upper()\r
1640 List = self.FixedMapDict.setdefault(Guid, [])\r
1641 List.append((AddressType, BaseAddress, "*I"))\r
1642 List.append((AddressType, EntryPoint, "*E"))\r
1643 except:\r
1644 EdkLogger.warn(None, "Cannot open file to read", self._MapFileName)\r
1645\r
1646 ##\r
1647 # Invokes EOT tool to get the predicted the execution order.\r
1648 #\r
1649 # This function invokes EOT tool to calculate the predicted dispatch order\r
1650 #\r
1651 # @param self: The object pointer\r
1652 #\r
1653 def _InvokeEotTool(self):\r
1654 if self._EotToolInvoked:\r
1655 return\r
1656\r
1657 self._EotToolInvoked = True\r
1658 FvFileList = []\r
1659 for FvName in self._FvList:\r
1660 FvFile = os.path.join(self._FvDir, FvName + ".Fv")\r
1661 if os.path.isfile(FvFile):\r
1662 FvFileList.append(FvFile)\r
1663\r
1664 if len(FvFileList) == 0:\r
1665 return\r
1666 #\r
1667 # Write source file list and GUID file list to an intermediate file\r
1668 # as the input for EOT tool and dispatch List as the output file\r
1669 # from EOT tool.\r
1670 #\r
1671 SourceList = os.path.join(self._EotDir, "SourceFile.txt")\r
1672 GuidList = os.path.join(self._EotDir, "GuidList.txt")\r
1673 DispatchList = os.path.join(self._EotDir, "Dispatch.txt")\r
1674\r
c196d1d1 1675 TempFile = []\r
52302d4d
LG
1676 for Item in self._SourceList:\r
1677 FileWrite(TempFile, Item)\r
c196d1d1
FB
1678 SaveFileOnChange(SourceList, "".join(TempFile), False)\r
1679 TempFile = []\r
52302d4d
LG
1680 for Key in self._GuidMap:\r
1681 FileWrite(TempFile, "%s %s" % (Key, self._GuidMap[Key]))\r
c196d1d1 1682 SaveFileOnChange(GuidList, "".join(TempFile), False)\r
52302d4d
LG
1683\r
1684 try:\r
47f15da1 1685 from Eot.EotMain import Eot\r
40d841f6 1686\r
52302d4d 1687 #\r
40d841f6 1688 # Invoke EOT tool and echo its runtime performance\r
52302d4d 1689 #\r
40d841f6 1690 EotStartTime = time.time()\r
52302d4d
LG
1691 Eot(CommandLineOption=False, SourceFileList=SourceList, GuidList=GuidList,\r
1692 FvFileList=' '.join(FvFileList), Dispatch=DispatchList, IsInit=True)\r
40d841f6
LG
1693 EotEndTime = time.time()\r
1694 EotDuration = time.strftime("%H:%M:%S", time.gmtime(int(round(EotEndTime - EotStartTime))))\r
1695 EdkLogger.quiet("EOT run time: %s\n" % EotDuration)\r
f7496d71 1696\r
52302d4d
LG
1697 #\r
1698 # Parse the output of EOT tool\r
1699 #\r
1700 for Line in open(DispatchList):\r
1701 if len(Line.split()) < 4:\r
1702 continue\r
1703 (Guid, Phase, FfsName, FilePath) = Line.split()\r
1704 Symbol = self._FfsEntryPoint.get(Guid, [FfsName, ""])[0]\r
1705 if len(Symbol) > self.MaxLen:\r
1706 self.MaxLen = len(Symbol)\r
1707 self.ItemList.append((Phase, Symbol, FilePath))\r
1708 except:\r
1709 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))\r
1710 EdkLogger.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")\r
1711\r
1712\r
1713 ##\r
1714 # Generate platform execution order report\r
1715 #\r
1716 # This function generates the predicted module execution order.\r
1717 #\r
1718 # @param self The object pointer\r
1719 # @param File The file object for report\r
1720 #\r
1721 def _GenerateExecutionOrderReport(self, File):\r
1722 self._InvokeEotTool()\r
1723 if len(self.ItemList) == 0:\r
1724 return\r
1725 FileWrite(File, gSectionStart)\r
1726 FileWrite(File, "Execution Order Prediction")\r
1727 FileWrite(File, "*P PEI phase")\r
1728 FileWrite(File, "*D DXE phase")\r
1729 FileWrite(File, "*E Module INF entry point name")\r
1730 FileWrite(File, "*N Module notification function name")\r
1731\r
1732 FileWrite(File, "Type %-*s %s" % (self.MaxLen, "Symbol", "Module INF Path"))\r
1733 FileWrite(File, gSectionSep)\r
1734 for Item in self.ItemList:\r
1735 FileWrite(File, "*%sE %-*s %s" % (Item[0], self.MaxLen, Item[1], Item[2]))\r
1736\r
1737 FileWrite(File, gSectionStart)\r
1738\r
1739 ##\r
1740 # Generate Fixed Address report.\r
1741 #\r
1742 # This function generate the predicted fixed address report for a module\r
1743 # specified by Guid.\r
1744 #\r
1745 # @param self The object pointer\r
1746 # @param File The file object for report\r
1747 # @param Guid The module Guid value.\r
1748 # @param NotifyList The list of all notify function in a module\r
1749 #\r
1750 def _GenerateFixedAddressReport(self, File, Guid, NotifyList):\r
1751 self._ParseMapFile()\r
1752 FixedAddressList = self.FixedMapDict.get(Guid)\r
1753 if not FixedAddressList:\r
1754 return\r
1755\r
1756 FileWrite(File, gSubSectionStart)\r
1757 FileWrite(File, "Fixed Address Prediction")\r
1758 FileWrite(File, "*I Image Loading Address")\r
1759 FileWrite(File, "*E Entry Point Address")\r
1760 FileWrite(File, "*N Notification Function Address")\r
1761 FileWrite(File, "*F Flash Address")\r
1762 FileWrite(File, "*M Memory Address")\r
1763 FileWrite(File, "*S SMM RAM Offset")\r
1764 FileWrite(File, "TOM Top of Memory")\r
1765\r
1766 FileWrite(File, "Type Address Name")\r
1767 FileWrite(File, gSubSectionSep)\r
1768 for Item in FixedAddressList:\r
1769 Type = Item[0]\r
1770 Value = Item[1]\r
1771 Symbol = Item[2]\r
1772 if Symbol == "*I":\r
1773 Name = "(Image Base)"\r
1774 elif Symbol == "*E":\r
1775 Name = self._FfsEntryPoint.get(Guid, ["", "_ModuleEntryPoint"])[1]\r
1776 elif Symbol in NotifyList:\r
1777 Name = Symbol\r
1778 Symbol = "*N"\r
1779 else:\r
1780 continue\r
1781\r
1782 if "Flash" in Type:\r
1783 Symbol += "F"\r
1784 elif "Memory" in Type:\r
1785 Symbol += "M"\r
1786 else:\r
1787 Symbol += "S"\r
1788\r
1789 if Value[0] == "-":\r
1790 Value = "TOM" + Value\r
1791\r
1792 FileWrite(File, "%s %-16s %s" % (Symbol, Value, Name))\r
1793\r
1794 ##\r
1795 # Generate report for the prediction part\r
1796 #\r
1797 # This function generate the predicted fixed address report for a module or\r
1798 # predicted module execution order for a platform.\r
1799 # If the input Guid is None, then, it generates the predicted module execution order;\r
1800 # otherwise it generated the module fixed loading address for the module specified by\r
1801 # Guid.\r
1802 #\r
1803 # @param self The object pointer\r
1804 # @param File The file object for report\r
1805 # @param Guid The module Guid value.\r
1806 #\r
1807 def GenerateReport(self, File, Guid):\r
1808 if Guid:\r
1809 self._GenerateFixedAddressReport(File, Guid.upper(), [])\r
1810 else:\r
1811 self._GenerateExecutionOrderReport(File)\r
1812\r
1813##\r
1814# Reports FD region information\r
1815#\r
1816# This class reports the FD subsection in the build report file.\r
1817# It collects region information of platform flash device.\r
1818# If the region is a firmware volume, it lists the set of modules\r
1819# and its space information; otherwise, it only lists its region name,\r
1820# base address and size in its sub-section header.\r
1821# If there are nesting FVs, the nested FVs will list immediate after\r
1822# this FD region subsection\r
1823#\r
1824class FdRegionReport(object):\r
1825 ##\r
1826 # Discover all the nested FV name list.\r
1827 #\r
1828 # This is an internal worker function to discover the all the nested FV information\r
1829 # in the parent firmware volume. It uses deep first search algorithm recursively to\r
1830 # find all the FV list name and append them to the list.\r
1831 #\r
1832 # @param self The object pointer\r
1833 # @param FvName The name of current firmware file system\r
1834 # @param Wa Workspace context information\r
1835 #\r
1836 def _DiscoverNestedFvList(self, FvName, Wa):\r
a2432972
EC
1837 FvDictKey=FvName.upper()\r
1838 if FvDictKey in Wa.FdfProfile.FvDict:\r
1839 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1840 for Section in Ffs.SectionList:\r
1841 try:\r
1842 for FvSection in Section.SectionList:\r
1843 if FvSection.FvName in self.FvList:\r
1844 continue\r
1845 self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName\r
1846 self.FvList.append(FvSection.FvName)\r
1847 self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0)\r
1848 self._DiscoverNestedFvList(FvSection.FvName, Wa)\r
1849 except AttributeError:\r
1850 pass\r
52302d4d
LG
1851\r
1852 ##\r
1853 # Constructor function for class FdRegionReport\r
1854 #\r
1855 # This constructor function generates FdRegionReport object for a specified FdRegion.\r
1856 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware\r
1857 # volume list. This function also collects GUID map in order to dump module identification\r
1858 # in the final report.\r
1859 #\r
1860 # @param self: The object pointer\r
1861 # @param FdRegion The current FdRegion object\r
1862 # @param Wa Workspace context information\r
1863 #\r
1864 def __init__(self, FdRegion, Wa):\r
1865 self.Type = FdRegion.RegionType\r
1866 self.BaseAddress = FdRegion.Offset\r
1867 self.Size = FdRegion.Size\r
1868 self.FvList = []\r
1869 self.FvInfo = {}\r
1870 self._GuidsDb = {}\r
1871 self._FvDir = Wa.FvDir\r
aebe5a36 1872 self._WorkspaceDir = Wa.WorkspaceDir\r
52302d4d
LG
1873\r
1874 #\r
1875 # If the input FdRegion is not a firmware volume,\r
1876 # we are done.\r
1877 #\r
91fa33ee 1878 if self.Type != BINARY_FILE_TYPE_FV:\r
52302d4d
LG
1879 return\r
1880\r
1881 #\r
1882 # Find all nested FVs in the FdRegion\r
1883 #\r
1884 for FvName in FdRegion.RegionDataList:\r
1885 if FvName in self.FvList:\r
1886 continue\r
1887 self.FvList.append(FvName)\r
1888 self.FvInfo[FvName] = ("Fd Region", self.BaseAddress, self.Size)\r
1889 self._DiscoverNestedFvList(FvName, Wa)\r
1890\r
1891 PlatformPcds = {}\r
52302d4d
LG
1892 #\r
1893 # Collect PCDs declared in DEC files.\r
f7496d71 1894 #\r
0d2711a6
LG
1895 for Pa in Wa.AutoGenObjectList:\r
1896 for Package in Pa.PackageList:\r
1897 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
1898 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
1899 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue\r
52302d4d 1900 #\r
af9785a9 1901 # Collect PCDs defined in DSC file\r
52302d4d 1902 #\r
e651d06c
LG
1903 for Pa in Wa.AutoGenObjectList:\r
1904 for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:\r
1905 DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
af9785a9 1906 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
52302d4d
LG
1907\r
1908 #\r
1909 # Add PEI and DXE a priori files GUIDs defined in PI specification.\r
1910 #\r
9e47e6f9
CJ
1911 self._GuidsDb[PEI_APRIORI_GUID] = "PEI Apriori"\r
1912 self._GuidsDb[DXE_APRIORI_GUID] = "DXE Apriori"\r
52302d4d
LG
1913 #\r
1914 # Add ACPI table storage file\r
1915 #\r
1916 self._GuidsDb["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"\r
1917\r
1918 for Pa in Wa.AutoGenObjectList:\r
1919 for ModuleKey in Pa.Platform.Modules:\r
1920 M = Pa.Platform.Modules[ModuleKey].M\r
05cc51ad 1921 InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File)\r
52302d4d
LG
1922 self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath)\r
1923\r
1924 #\r
1925 # Collect the GUID map in the FV firmware volume\r
1926 #\r
1927 for FvName in self.FvList:\r
a2432972
EC
1928 FvDictKey=FvName.upper()\r
1929 if FvDictKey in Wa.FdfProfile.FvDict:\r
1930 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1931 try:\r
1932 #\r
1933 # collect GUID map for binary EFI file in FDF file.\r
1934 #\r
1935 Guid = Ffs.NameGuid.upper()\r
1936 Match = gPcdGuidPattern.match(Ffs.NameGuid)\r
1937 if Match:\r
1938 PcdTokenspace = Match.group(1)\r
1939 PcdToken = Match.group(2)\r
1940 if (PcdToken, PcdTokenspace) in PlatformPcds:\r
1941 GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)]\r
1942 Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()\r
1943 for Section in Ffs.SectionList:\r
1944 try:\r
1945 ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName)\r
1946 self._GuidsDb[Guid] = ModuleSectFile\r
1947 except AttributeError:\r
1948 pass\r
1949 except AttributeError:\r
1950 pass\r
52302d4d
LG
1951\r
1952\r
1953 ##\r
1954 # Internal worker function to generate report for the FD region\r
1955 #\r
1956 # This internal worker function to generate report for the FD region.\r
1957 # It the type is firmware volume, it lists offset and module identification.\r
1958 #\r
1959 # @param self The object pointer\r
1960 # @param File The file object for report\r
1961 # @param Title The title for the FD subsection\r
1962 # @param BaseAddress The base address for the FD region\r
1963 # @param Size The size of the FD region\r
1964 # @param FvName The FV name if the FD region is a firmware volume\r
1965 #\r
1966 def _GenerateReport(self, File, Title, Type, BaseAddress, Size=0, FvName=None):\r
1967 FileWrite(File, gSubSectionStart)\r
1968 FileWrite(File, Title)\r
1969 FileWrite(File, "Type: %s" % Type)\r
1970 FileWrite(File, "Base Address: 0x%X" % BaseAddress)\r
1971\r
91fa33ee 1972 if self.Type == BINARY_FILE_TYPE_FV:\r
52302d4d
LG
1973 FvTotalSize = 0\r
1974 FvTakenSize = 0\r
1975 FvFreeSize = 0\r
aebe5a36
YZ
1976 if FvName.upper().endswith('.FV'):\r
1977 FileExt = FvName + ".txt"\r
2157bc9c 1978 else:\r
aebe5a36
YZ
1979 FileExt = FvName + ".Fv.txt"\r
1980\r
1981 if not os.path.isfile(FileExt):\r
1982 FvReportFileName = mws.join(self._WorkspaceDir, FileExt)\r
1983 if not os.path.isfile(FvReportFileName):\r
1984 FvReportFileName = os.path.join(self._FvDir, FileExt)\r
52302d4d
LG
1985 try:\r
1986 #\r
1987 # Collect size info in the firmware volume.\r
1988 #\r
1989 FvReport = open(FvReportFileName).read()\r
1990 Match = gFvTotalSizePattern.search(FvReport)\r
1991 if Match:\r
1992 FvTotalSize = int(Match.group(1), 16)\r
1993 Match = gFvTakenSizePattern.search(FvReport)\r
1994 if Match:\r
1995 FvTakenSize = int(Match.group(1), 16)\r
1996 FvFreeSize = FvTotalSize - FvTakenSize\r
1997 #\r
1998 # Write size information to the report file.\r
1999 #\r
2000 FileWrite(File, "Size: 0x%X (%.0fK)" % (FvTotalSize, FvTotalSize / 1024.0))\r
2001 FileWrite(File, "Fv Name: %s (%.1f%% Full)" % (FvName, FvTakenSize * 100.0 / FvTotalSize))\r
2002 FileWrite(File, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize, FvTakenSize / 1024.0))\r
2003 FileWrite(File, "Free Size: 0x%X (%.0fK)" % (FvFreeSize, FvFreeSize / 1024.0))\r
2004 FileWrite(File, "Offset Module")\r
2005 FileWrite(File, gSubSectionSep)\r
2006 #\r
2007 # Write module offset and module identification to the report file.\r
2008 #\r
2009 OffsetInfo = {}\r
2010 for Match in gOffsetGuidPattern.finditer(FvReport):\r
2011 Guid = Match.group(2).upper()\r
2012 OffsetInfo[Match.group(1)] = self._GuidsDb.get(Guid, Guid)\r
0d1f5b2b 2013 OffsetList = sorted(OffsetInfo.keys())\r
52302d4d
LG
2014 for Offset in OffsetList:\r
2015 FileWrite (File, "%s %s" % (Offset, OffsetInfo[Offset]))\r
2016 except IOError:\r
2017 EdkLogger.warn(None, "Fail to read report file", FvReportFileName)\r
2018 else:\r
2019 FileWrite(File, "Size: 0x%X (%.0fK)" % (Size, Size / 1024.0))\r
2020 FileWrite(File, gSubSectionEnd)\r
2021\r
2022 ##\r
2023 # Generate report for the FD region\r
2024 #\r
2025 # This function generates report for the FD region.\r
2026 #\r
2027 # @param self The object pointer\r
2028 # @param File The file object for report\r
2029 #\r
2030 def GenerateReport(self, File):\r
2031 if (len(self.FvList) > 0):\r
2032 for FvItem in self.FvList:\r
2033 Info = self.FvInfo[FvItem]\r
91fa33ee 2034 self._GenerateReport(File, Info[0], TAB_FV_DIRECTORY, Info[1], Info[2], FvItem)\r
52302d4d
LG
2035 else:\r
2036 self._GenerateReport(File, "FD Region", self.Type, self.BaseAddress, self.Size)\r
2037\r
2038##\r
2039# Reports FD information\r
2040#\r
2041# This class reports the FD section in the build report file.\r
2042# It collects flash device information for a platform.\r
2043#\r
2044class FdReport(object):\r
2045 ##\r
2046 # Constructor function for class FdReport\r
2047 #\r
2048 # This constructor function generates FdReport object for a specified\r
2049 # firmware device.\r
2050 #\r
2051 # @param self The object pointer\r
2052 # @param Fd The current Firmware device object\r
2053 # @param Wa Workspace context information\r
2054 #\r
2055 def __init__(self, Fd, Wa):\r
2056 self.FdName = Fd.FdUiName\r
2057 self.BaseAddress = Fd.BaseAddress\r
2058 self.Size = Fd.Size\r
2059 self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList]\r
91fa33ee 2060 self.FvPath = os.path.join(Wa.BuildDir, TAB_FV_DIRECTORY)\r
043928da
YZ
2061 self.VPDBaseAddress = 0\r
2062 self.VPDSize = 0\r
fb3d2279 2063 for index, FdRegion in enumerate(Fd.RegionList):\r
ec97412b 2064 if str(FdRegion.RegionType) == 'FILE' and Wa.Platform.VpdToolGuid in str(FdRegion.RegionDataList):\r
fb3d2279
YZ
2065 self.VPDBaseAddress = self.FdRegionList[index].BaseAddress\r
2066 self.VPDSize = self.FdRegionList[index].Size\r
2067 break\r
2068\r
52302d4d
LG
2069 ##\r
2070 # Generate report for the firmware device.\r
2071 #\r
2072 # This function generates report for the firmware device.\r
2073 #\r
2074 # @param self The object pointer\r
2075 # @param File The file object for report\r
2076 #\r
2077 def GenerateReport(self, File):\r
2078 FileWrite(File, gSectionStart)\r
2079 FileWrite(File, "Firmware Device (FD)")\r
2080 FileWrite(File, "FD Name: %s" % self.FdName)\r
2081 FileWrite(File, "Base Address: %s" % self.BaseAddress)\r
2082 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.Size, self.Size / 1024.0))\r
2083 if len(self.FdRegionList) > 0:\r
2084 FileWrite(File, gSectionSep)\r
2085 for FdRegionItem in self.FdRegionList:\r
2086 FdRegionItem.GenerateReport(File)\r
2087\r
ebed920f
YZ
2088 if VPDPcdList:\r
2089 VPDPcdList.sort(key=lambda x: int(x[2], 0))\r
fb3d2279
YZ
2090 FileWrite(File, gSubSectionStart)\r
2091 FileWrite(File, "FD VPD Region")\r
2092 FileWrite(File, "Base Address: 0x%X" % self.VPDBaseAddress)\r
2093 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.VPDSize, self.VPDSize / 1024.0))\r
2094 FileWrite(File, gSubSectionSep)\r
ebed920f
YZ
2095 for item in VPDPcdList:\r
2096 # Add BaseAddress for offset\r
2097 Offset = '0x%08X' % (int(item[2], 16) + self.VPDBaseAddress)\r
2098 IsByteArray, ArrayList = ByteArrayForamt(item[-1])\r
2099 Skuinfo = item[1]\r
2100 if len(GlobalData.gSkuids) == 1 :\r
2101 Skuinfo = GlobalData.gSkuids[0]\r
e651d06c 2102 if IsByteArray:\r
ebed920f 2103 FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], '{'))\r
e651d06c 2104 for Array in ArrayList:\r
caf74495 2105 FileWrite(File, Array)\r
e651d06c 2106 else:\r
ebed920f 2107 FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], item[-1]))\r
fb3d2279 2108 FileWrite(File, gSubSectionEnd)\r
52302d4d
LG
2109 FileWrite(File, gSectionEnd)\r
2110\r
2111\r
2112\r
2113##\r
2114# Reports platform information\r
2115#\r
2116# This class reports the whole platform information\r
2117#\r
2118class PlatformReport(object):\r
2119 ##\r
2120 # Constructor function for class PlatformReport\r
2121 #\r
2122 # This constructor function generates PlatformReport object a platform build.\r
2123 # It generates report for platform summary, flash, global PCDs and detailed\r
2124 # module information for modules involved in platform build.\r
2125 #\r
2126 # @param self The object pointer\r
2127 # @param Wa Workspace context information\r
d5d56f1b 2128 # @param MaList The list of modules in the platform build\r
52302d4d 2129 #\r
d5d56f1b 2130 def __init__(self, Wa, MaList, ReportType):\r
52302d4d
LG
2131 self._WorkspaceDir = Wa.WorkspaceDir\r
2132 self.PlatformName = Wa.Name\r
2133 self.PlatformDscPath = Wa.Platform\r
2134 self.Architectures = " ".join(Wa.ArchList)\r
2135 self.ToolChain = Wa.ToolChain\r
2136 self.Target = Wa.BuildTarget\r
2137 self.OutputPath = os.path.join(Wa.WorkspaceDir, Wa.OutputDir)\r
2138 self.BuildEnvironment = platform.platform()\r
2139\r
2140 self.PcdReport = None\r
2141 if "PCD" in ReportType:\r
2142 self.PcdReport = PcdReport(Wa)\r
2143\r
2144 self.FdReportList = []\r
4231a819 2145 if "FLASH" in ReportType and Wa.FdfProfile and MaList is None:\r
52302d4d
LG
2146 for Fd in Wa.FdfProfile.FdDict:\r
2147 self.FdReportList.append(FdReport(Wa.FdfProfile.FdDict[Fd], Wa))\r
2148\r
2149 self.PredictionReport = None\r
2150 if "FIXED_ADDRESS" in ReportType or "EXECUTION_ORDER" in ReportType:\r
2151 self.PredictionReport = PredictionReport(Wa)\r
2152\r
e56468c0 2153 self.DepexParser = None\r
2154 if "DEPEX" in ReportType:\r
2155 self.DepexParser = DepexParser(Wa)\r
f7496d71 2156\r
52302d4d 2157 self.ModuleReportList = []\r
4231a819 2158 if MaList is not None:\r
636f2be6 2159 self._IsModuleBuild = True\r
d5d56f1b
LG
2160 for Ma in MaList:\r
2161 self.ModuleReportList.append(ModuleReport(Ma, ReportType))\r
2162 else:\r
636f2be6 2163 self._IsModuleBuild = False\r
d5d56f1b 2164 for Pa in Wa.AutoGenObjectList:\r
25193a33 2165 ModuleAutoGenList = []\r
d5d56f1b 2166 for ModuleKey in Pa.Platform.Modules:\r
25193a33 2167 ModuleAutoGenList.append(Pa.Platform.Modules[ModuleKey].M)\r
4231a819 2168 if GlobalData.gFdfParser is not None:\r
25193a33
YZ
2169 if Pa.Arch in GlobalData.gFdfParser.Profile.InfDict:\r
2170 INFList = GlobalData.gFdfParser.Profile.InfDict[Pa.Arch]\r
2171 for InfName in INFList:\r
2172 InfClass = PathClass(NormPath(InfName), Wa.WorkspaceDir, Pa.Arch)\r
0970a805 2173 Ma = ModuleAutoGen(Wa, InfClass, Pa.BuildTarget, Pa.ToolChain, Pa.Arch, Wa.MetaFile, Pa.DataPipe)\r
4231a819 2174 if Ma is None:\r
25193a33
YZ
2175 continue\r
2176 if Ma not in ModuleAutoGenList:\r
2177 ModuleAutoGenList.append(Ma)\r
2178 for MGen in ModuleAutoGenList:\r
2179 self.ModuleReportList.append(ModuleReport(MGen, ReportType))\r
52302d4d
LG
2180\r
2181\r
2182\r
2183 ##\r
2184 # Generate report for the whole platform.\r
2185 #\r
2186 # This function generates report for platform information.\r
2187 # It comprises of platform summary, global PCD, flash and\r
2188 # module list sections.\r
2189 #\r
2190 # @param self The object pointer\r
2191 # @param File The file object for report\r
2192 # @param BuildDuration The total time to build the modules\r
1b8eca8b
YZ
2193 # @param AutoGenTime The total time of AutoGen Phase\r
2194 # @param MakeTime The total time of Make Phase\r
2195 # @param GenFdsTime The total time of GenFds Phase\r
52302d4d
LG
2196 # @param ReportType The kind of report items in the final report file\r
2197 #\r
1b8eca8b 2198 def GenerateReport(self, File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, ReportType):\r
52302d4d
LG
2199 FileWrite(File, "Platform Summary")\r
2200 FileWrite(File, "Platform Name: %s" % self.PlatformName)\r
2201 FileWrite(File, "Platform DSC Path: %s" % self.PlatformDscPath)\r
2202 FileWrite(File, "Architectures: %s" % self.Architectures)\r
2203 FileWrite(File, "Tool Chain: %s" % self.ToolChain)\r
2204 FileWrite(File, "Target: %s" % self.Target)\r
e651d06c
LG
2205 if GlobalData.gSkuids:\r
2206 FileWrite(File, "SKUID: %s" % " ".join(GlobalData.gSkuids))\r
2207 if GlobalData.gDefaultStores:\r
2208 FileWrite(File, "DefaultStore: %s" % " ".join(GlobalData.gDefaultStores))\r
52302d4d
LG
2209 FileWrite(File, "Output Path: %s" % self.OutputPath)\r
2210 FileWrite(File, "Build Environment: %s" % self.BuildEnvironment)\r
2211 FileWrite(File, "Build Duration: %s" % BuildDuration)\r
1b8eca8b
YZ
2212 if AutoGenTime:\r
2213 FileWrite(File, "AutoGen Duration: %s" % AutoGenTime)\r
2214 if MakeTime:\r
2215 FileWrite(File, "Make Duration: %s" % MakeTime)\r
2216 if GenFdsTime:\r
2217 FileWrite(File, "GenFds Duration: %s" % GenFdsTime)\r
52302d4d
LG
2218 FileWrite(File, "Report Content: %s" % ", ".join(ReportType))\r
2219\r
2a29017e
YZ
2220 if GlobalData.MixedPcd:\r
2221 FileWrite(File, gSectionStart)\r
2222 FileWrite(File, "The following PCDs use different access methods:")\r
2223 FileWrite(File, gSectionSep)\r
2224 for PcdItem in GlobalData.MixedPcd:\r
2225 FileWrite(File, "%s.%s" % (str(PcdItem[1]), str(PcdItem[0])))\r
2226 FileWrite(File, gSectionEnd)\r
2227\r
636f2be6
LG
2228 if not self._IsModuleBuild:\r
2229 if "PCD" in ReportType:\r
2230 self.PcdReport.GenerateReport(File, None)\r
f7496d71 2231\r
636f2be6
LG
2232 if "FLASH" in ReportType:\r
2233 for FdReportListItem in self.FdReportList:\r
2234 FdReportListItem.GenerateReport(File)\r
52302d4d
LG
2235\r
2236 for ModuleReportItem in self.ModuleReportList:\r
e56468c0 2237 ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, self.DepexParser, ReportType)\r
52302d4d 2238\r
636f2be6
LG
2239 if not self._IsModuleBuild:\r
2240 if "EXECUTION_ORDER" in ReportType:\r
2241 self.PredictionReport.GenerateReport(File, None)\r
52302d4d
LG
2242\r
2243## BuildReport class\r
2244#\r
2245# This base class contain the routines to collect data and then\r
2246# applies certain format to the output report\r
2247#\r
2248class BuildReport(object):\r
2249 ##\r
2250 # Constructor function for class BuildReport\r
2251 #\r
2252 # This constructor function generates BuildReport object a platform build.\r
2253 # It generates report for platform summary, flash, global PCDs and detailed\r
2254 # module information for modules involved in platform build.\r
2255 #\r
2256 # @param self The object pointer\r
2257 # @param ReportFile The file name to save report file\r
2258 # @param ReportType The kind of report items in the final report file\r
2259 #\r
2260 def __init__(self, ReportFile, ReportType):\r
2261 self.ReportFile = ReportFile\r
2262 if ReportFile:\r
2263 self.ReportList = []\r
2264 self.ReportType = []\r
f7496d71 2265 if ReportType:\r
52302d4d
LG
2266 for ReportTypeItem in ReportType:\r
2267 if ReportTypeItem not in self.ReportType:\r
2268 self.ReportType.append(ReportTypeItem)\r
2269 else:\r
eca5be7a 2270 self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]\r
52302d4d
LG
2271 ##\r
2272 # Adds platform report to the list\r
2273 #\r
2274 # This function adds a platform report to the final report list.\r
2275 #\r
2276 # @param self The object pointer\r
2277 # @param Wa Workspace context information\r
d5d56f1b 2278 # @param MaList The list of modules in the platform build\r
52302d4d 2279 #\r
d5d56f1b 2280 def AddPlatformReport(self, Wa, MaList=None):\r
52302d4d 2281 if self.ReportFile:\r
d5d56f1b 2282 self.ReportList.append((Wa, MaList))\r
52302d4d
LG
2283\r
2284 ##\r
2285 # Generates the final report.\r
2286 #\r
2287 # This function generates platform build report. It invokes GenerateReport()\r
2288 # method for every platform report in the list.\r
2289 #\r
2290 # @param self The object pointer\r
2291 # @param BuildDuration The total time to build the modules\r
1b8eca8b
YZ
2292 # @param AutoGenTime The total time of AutoGen phase\r
2293 # @param MakeTime The total time of Make phase\r
2294 # @param GenFdsTime The total time of GenFds phase\r
52302d4d 2295 #\r
1b8eca8b 2296 def GenerateReport(self, BuildDuration, AutoGenTime, MakeTime, GenFdsTime):\r
52302d4d
LG
2297 if self.ReportFile:\r
2298 try:\r
d943b0c3 2299 File = []\r
d5d56f1b 2300 for (Wa, MaList) in self.ReportList:\r
1b8eca8b 2301 PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, self.ReportType)\r
d943b0c3
FB
2302 Content = FileLinesSplit(''.join(File), gLineMaxLength)\r
2303 SaveFileOnChange(self.ReportFile, Content, False)\r
40d841f6 2304 EdkLogger.quiet("Build report can be found at %s" % os.path.abspath(self.ReportFile))\r
52302d4d
LG
2305 except IOError:\r
2306 EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)\r
2307 except:\r
2308 EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report", ExtraData=self.ReportFile, RaiseError=False)\r
2309 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))\r
f7496d71 2310\r
52302d4d
LG
2311# This acts like the main() function for the script, unless it is 'import'ed into another script.\r
2312if __name__ == '__main__':\r
2313 pass\r
2314\r