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