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