]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/build/BuildReport.py
MdeModulePkg/DriverSample: Add questions with bit/union VarStore
[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
7cb63c87 7# Copyright (c) 2010 - 2017, 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
40d841f6 31from StringIO import StringIO\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
36from Common.InfClassObject import gComponentType2ModuleType\r
52302d4d
LG
37from Common.BuildToolError import FILE_WRITE_FAILURE\r
38from Common.BuildToolError import CODE_ERROR\r
eca5be7a 39from Common.BuildToolError import COMMAND_FAILURE\r
64b2609f
LG
40from Common.DataType import TAB_LINE_BREAK\r
41from Common.DataType import TAB_DEPEX\r
42from Common.DataType import TAB_SLASH\r
43from Common.DataType import TAB_SPACE_SPLIT\r
44from Common.DataType import TAB_BRG_PCD\r
45from Common.DataType import TAB_BRG_LIBRARY\r
25918452 46from Common.DataType import TAB_BACK_SLASH\r
1be2ed90 47from Common.LongFilePathSupport import OpenLongFilePath as open\r
05cc51ad 48from Common.MultipleWorkspace import MultipleWorkspace as mws\r
763e8edf 49import Common.GlobalData as GlobalData\r
25193a33
YZ
50from AutoGen.AutoGen import ModuleAutoGen\r
51from Common.Misc import PathClass\r
52from Common.String import NormPath\r
52302d4d
LG
53\r
54## Pattern to extract contents in EDK DXS files\r
55gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)\r
56\r
57## Pattern to find total FV total size, occupied size in flash report intermediate file\r
58gFvTotalSizePattern = re.compile(r"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")\r
59gFvTakenSizePattern = re.compile(r"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")\r
60\r
61## Pattern to find module size and time stamp in module summary report intermediate file\r
62gModuleSizePattern = re.compile(r"MODULE_SIZE = (\d+)")\r
63gTimeStampPattern = re.compile(r"TIME_STAMP = (\d+)")\r
64\r
65## Pattern to find GUID value in flash description files\r
66gPcdGuidPattern = re.compile(r"PCD\((\w+)[.](\w+)\)")\r
67\r
68## Pattern to collect offset, GUID value pair in the flash report intermediate file\r
69gOffsetGuidPattern = re.compile(r"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")\r
70\r
71## Pattern to find module base address and entry point in fixed flash map file\r
72gModulePattern = r"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"\r
73gMapFileItemPattern = re.compile(gModulePattern % {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})\r
74\r
75## Pattern to find all module referenced header files in source files\r
76gIncludePattern = re.compile(r'#include\s*["<]([^">]+)[">]')\r
77gIncludePattern2 = re.compile(r"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")\r
78\r
79## Pattern to find the entry point for EDK module using EDKII Glue library\r
80gGlueLibEntryPoint = re.compile(r"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")\r
81\r
64b2609f
LG
82## Tags for MaxLength of line in report\r
83gLineMaxLength = 120\r
84\r
4afd3d04
LG
85## Tags for end of line in report\r
86gEndOfLine = "\r\n"\r
87\r
52302d4d 88## Tags for section start, end and separator\r
47fea6af
YZ
89gSectionStart = ">" + "=" * (gLineMaxLength - 2) + "<"\r
90gSectionEnd = "<" + "=" * (gLineMaxLength - 2) + ">" + "\n"\r
64b2609f 91gSectionSep = "=" * gLineMaxLength\r
52302d4d
LG
92\r
93## Tags for subsection start, end and separator\r
47fea6af
YZ
94gSubSectionStart = ">" + "-" * (gLineMaxLength - 2) + "<"\r
95gSubSectionEnd = "<" + "-" * (gLineMaxLength - 2) + ">"\r
64b2609f
LG
96gSubSectionSep = "-" * gLineMaxLength\r
97\r
52302d4d
LG
98\r
99## The look up table to map PCD type to pair of report display type and DEC type\r
100gPcdTypeMap = {\r
101 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),\r
102 'PatchableInModule': ('PATCH', 'PatchableInModule'),\r
103 'FeatureFlag' : ('FLAG', 'FeatureFlag'),\r
104 'Dynamic' : ('DYN', 'Dynamic'),\r
105 'DynamicHii' : ('DYNHII', 'Dynamic'),\r
106 'DynamicVpd' : ('DYNVPD', 'Dynamic'),\r
4afd3d04
LG
107 'DynamicEx' : ('DEX', 'DynamicEx'),\r
108 'DynamicExHii' : ('DEXHII', 'DynamicEx'),\r
109 'DynamicExVpd' : ('DEXVPD', 'DynamicEx'),\r
52302d4d
LG
110 }\r
111\r
112## The look up table to map module type to driver type\r
113gDriverTypeMap = {\r
114 'SEC' : '0x3 (SECURITY_CORE)',\r
115 'PEI_CORE' : '0x4 (PEI_CORE)',\r
116 'PEIM' : '0x6 (PEIM)',\r
117 'DXE_CORE' : '0x5 (DXE_CORE)',\r
118 'DXE_DRIVER' : '0x7 (DRIVER)',\r
119 'DXE_SAL_DRIVER' : '0x7 (DRIVER)',\r
120 'DXE_SMM_DRIVER' : '0x7 (DRIVER)',\r
121 'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',\r
122 'UEFI_DRIVER' : '0x7 (DRIVER)',\r
123 'UEFI_APPLICATION' : '0x9 (APPLICATION)',\r
124 'SMM_CORE' : '0xD (SMM_CORE)',\r
125 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers\r
e574123c
SV
126 'MM_STANDALONE' : '0xE (MM_STANDALONE)',\r
127 'MM_CORE_STANDALONE' : '0xF (MM_CORE_STANDALONE)'\r
52302d4d
LG
128 }\r
129\r
e56468c0 130## The look up table of the supported opcode in the dependency expression binaries\r
131gOpCodeList = ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]\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
LG
147\r
148##\r
149# Find all the header file that the module source directly includes.\r
150#\r
151# This function scans source code to find all header files the module may\r
152# include. This is not accurate but very effective to find all the header\r
153# file the module might include with #include statement.\r
154#\r
155# @Source The source file name\r
156# @IncludePathList The list of include path to find the source file.\r
157# @IncludeFiles The dictionary of current found include files.\r
158#\r
159def FindIncludeFiles(Source, IncludePathList, IncludeFiles):\r
160 FileContents = open(Source).read()\r
161 #\r
162 # Find header files with pattern #include "XXX.h" or #include <XXX.h>\r
163 #\r
164 for Match in gIncludePattern.finditer(FileContents):\r
165 FileName = Match.group(1).strip()\r
166 for Dir in [os.path.dirname(Source)] + IncludePathList:\r
167 FullFileName = os.path.normpath(os.path.join(Dir, FileName))\r
168 if os.path.exists(FullFileName):\r
169 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName\r
170 break\r
171\r
172 #\r
173 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)\r
174 #\r
175 for Match in gIncludePattern2.finditer(FileContents):\r
176 Key = Match.group(2)\r
177 Type = Match.group(1)\r
178 if "ARCH_PROTOCOL" in Type:\r
179 FileName = "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
180 elif "PROTOCOL" in Type:\r
181 FileName = "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
182 elif "PPI" in Type:\r
183 FileName = "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
184 elif "GUID" in Type:\r
185 FileName = "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key}\r
186 else:\r
187 continue\r
188 for Dir in IncludePathList:\r
189 FullFileName = os.path.normpath(os.path.join(Dir, FileName))\r
190 if os.path.exists(FullFileName):\r
191 IncludeFiles[FullFileName.lower().replace("\\", "/")] = FullFileName\r
192 break\r
193\r
64b2609f
LG
194## Split each lines in file\r
195#\r
196# This method is used to split the lines in file to make the length of each line \r
197# less than MaxLength.\r
198#\r
199# @param Content The content of file\r
200# @param MaxLength The Max Length of the line\r
201#\r
202def FileLinesSplit(Content=None, MaxLength=None):\r
203 ContentList = Content.split(TAB_LINE_BREAK)\r
204 NewContent = ''\r
205 NewContentList = []\r
206 for Line in ContentList:\r
207 while len(Line.rstrip()) > MaxLength:\r
208 LineSpaceIndex = Line.rfind(TAB_SPACE_SPLIT, 0, MaxLength)\r
209 LineSlashIndex = Line.rfind(TAB_SLASH, 0, MaxLength)\r
25918452
LG
210 LineBackSlashIndex = Line.rfind(TAB_BACK_SLASH, 0, MaxLength)\r
211 if max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex) > 0:\r
212 LineBreakIndex = max(LineSpaceIndex, LineSlashIndex, LineBackSlashIndex)\r
213 else:\r
214 LineBreakIndex = MaxLength\r
64b2609f
LG
215 NewContentList.append(Line[:LineBreakIndex])\r
216 Line = Line[LineBreakIndex:]\r
217 if Line:\r
218 NewContentList.append(Line)\r
219 for NewLine in NewContentList:\r
220 NewContent += NewLine + TAB_LINE_BREAK\r
4afd3d04
LG
221 \r
222 NewContent = NewContent.replace(TAB_LINE_BREAK, gEndOfLine).replace('\r\r\n', gEndOfLine)\r
64b2609f
LG
223 return NewContent\r
224 \r
225 \r
226 \r
e56468c0 227##\r
228# Parse binary dependency expression section\r
229#\r
230# This utility class parses the dependency expression section and translate the readable\r
231# GUID name and value.\r
232#\r
233class DepexParser(object):\r
234 ##\r
235 # Constructor function for class DepexParser\r
236 #\r
237 # This constructor function collect GUID values so that the readable\r
238 # GUID name can be translated.\r
239 #\r
240 # @param self The object pointer\r
241 # @param Wa Workspace context information\r
242 #\r
243 def __init__(self, Wa):\r
244 self._GuidDb = {}\r
0d2711a6 245 for Pa in Wa.AutoGenObjectList:\r
47fea6af 246 for Package in Pa.PackageList:\r
0d2711a6
LG
247 for Protocol in Package.Protocols:\r
248 GuidValue = GuidStructureStringToGuidString(Package.Protocols[Protocol])\r
249 self._GuidDb[GuidValue.upper()] = Protocol\r
250 for Ppi in Package.Ppis:\r
251 GuidValue = GuidStructureStringToGuidString(Package.Ppis[Ppi])\r
252 self._GuidDb[GuidValue.upper()] = Ppi\r
253 for Guid in Package.Guids:\r
254 GuidValue = GuidStructureStringToGuidString(Package.Guids[Guid])\r
255 self._GuidDb[GuidValue.upper()] = Guid\r
e56468c0 256 \r
257 ##\r
258 # Parse the binary dependency expression files.\r
259 # \r
260 # This function parses the binary dependency expression file and translate it\r
261 # to the instruction list.\r
262 #\r
263 # @param self The object pointer\r
264 # @param DepexFileName The file name of binary dependency expression file.\r
265 #\r
266 def ParseDepexFile(self, DepexFileName):\r
267 DepexFile = open(DepexFileName, "rb")\r
268 DepexStatement = []\r
269 OpCode = DepexFile.read(1)\r
270 while OpCode:\r
271 Statement = gOpCodeList[struct.unpack("B", OpCode)[0]]\r
272 if Statement in ["BEFORE", "AFTER", "PUSH"]:\r
273 GuidValue = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \\r
2bc3256c 274 struct.unpack("=LHHBBBBBBBB", DepexFile.read(16))\r
e56468c0 275 GuidString = self._GuidDb.get(GuidValue, GuidValue)\r
276 Statement = "%s %s" % (Statement, GuidString)\r
277 DepexStatement.append(Statement)\r
47fea6af
YZ
278 OpCode = DepexFile.read(1)\r
279\r
e56468c0 280 return DepexStatement\r
281 \r
52302d4d
LG
282##\r
283# Reports library information\r
284#\r
285# This class reports the module library subsection in the build report file.\r
286#\r
287class LibraryReport(object):\r
288 ##\r
289 # Constructor function for class LibraryReport\r
290 #\r
291 # This constructor function generates LibraryReport object for\r
292 # a module.\r
293 #\r
294 # @param self The object pointer\r
295 # @param M Module context information\r
296 #\r
297 def __init__(self, M):\r
298 self.LibraryList = []\r
299 if int(str(M.AutoGenVersion), 0) >= 0x00010005:\r
300 self._EdkIIModule = True\r
301 else:\r
302 self._EdkIIModule = False\r
303\r
304 for Lib in M.DependentLibraryList:\r
305 LibInfPath = str(Lib)\r
306 LibClassList = Lib.LibraryClass[0].LibraryClass\r
307 LibConstructorList = Lib.ConstructorList\r
308 LibDesstructorList = Lib.DestructorList\r
309 LibDepexList = Lib.DepexExpression[M.Arch, M.ModuleType]\r
1b8eca8b
YZ
310 for LibAutoGen in M.LibraryAutoGenList:\r
311 if LibInfPath == LibAutoGen.MetaFile.Path:\r
312 LibTime = LibAutoGen.BuildTime\r
313 break\r
314 self.LibraryList.append((LibInfPath, LibClassList, LibConstructorList, LibDesstructorList, LibDepexList, LibTime))\r
52302d4d
LG
315\r
316 ##\r
317 # Generate report for module library information\r
318 #\r
319 # This function generates report for the module library.\r
320 # If the module is EDKII style one, the additional library class, library\r
321 # constructor/destructor and dependency expression may also be reported.\r
322 #\r
323 # @param self The object pointer\r
324 # @param File The file object for report\r
325 #\r
326 def GenerateReport(self, File):\r
52302d4d 327 if len(self.LibraryList) > 0:\r
c2d0a1f6
YZ
328 FileWrite(File, gSubSectionStart)\r
329 FileWrite(File, TAB_BRG_LIBRARY)\r
52302d4d
LG
330 FileWrite(File, gSubSectionSep)\r
331 for LibraryItem in self.LibraryList:\r
332 LibInfPath = LibraryItem[0]\r
333 FileWrite(File, LibInfPath)\r
334\r
335 #\r
336 # Report library class, library constructor and destructor for\r
337 # EDKII style module.\r
338 #\r
339 if self._EdkIIModule:\r
340 LibClass = LibraryItem[1]\r
341 EdkIILibInfo = ""\r
342 LibConstructor = " ".join(LibraryItem[2])\r
343 if LibConstructor:\r
344 EdkIILibInfo += " C = " + LibConstructor\r
345 LibDestructor = " ".join(LibraryItem[3])\r
346 if LibDestructor:\r
636f2be6 347 EdkIILibInfo += " D = " + LibDestructor\r
52302d4d
LG
348 LibDepex = " ".join(LibraryItem[4])\r
349 if LibDepex:\r
350 EdkIILibInfo += " Depex = " + LibDepex\r
1b8eca8b
YZ
351 if LibraryItem[5]:\r
352 EdkIILibInfo += " Time = " + LibraryItem[5]\r
52302d4d
LG
353 if EdkIILibInfo:\r
354 FileWrite(File, "{%s: %s}" % (LibClass, EdkIILibInfo))\r
355 else:\r
356 FileWrite(File, "{%s}" % LibClass)\r
357\r
c2d0a1f6 358 FileWrite(File, gSubSectionEnd)\r
52302d4d
LG
359\r
360##\r
361# Reports dependency expression information\r
362#\r
363# This class reports the module dependency expression subsection in the build report file.\r
364#\r
365class DepexReport(object):\r
366 ##\r
367 # Constructor function for class DepexReport\r
368 #\r
369 # This constructor function generates DepexReport object for\r
370 # a module. If the module source contains the DXS file (usually EDK\r
371 # style module), it uses the dependency in DXS file; otherwise,\r
372 # it uses the dependency expression from its own INF [Depex] section\r
373 # and then merges with the ones from its dependent library INF.\r
374 #\r
375 # @param self The object pointer\r
376 # @param M Module context information\r
377 #\r
378 def __init__(self, M):\r
379 self.Depex = ""\r
47fea6af 380 self._DepexFileName = os.path.join(M.BuildDir, "OUTPUT", M.Module.BaseName + ".depex")\r
52302d4d
LG
381 ModuleType = M.ModuleType\r
382 if not ModuleType:\r
383 ModuleType = gComponentType2ModuleType.get(M.ComponentType, "")\r
636f2be6 384\r
e574123c 385 if ModuleType in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "MM_CORE_STANDALONE", "UEFI_APPLICATION"]:\r
52302d4d
LG
386 return\r
387 \r
388 for Source in M.SourceFileList:\r
389 if os.path.splitext(Source.Path)[1].lower() == ".dxs":\r
390 Match = gDxsDependencyPattern.search(open(Source.Path).read())\r
391 if Match:\r
392 self.Depex = Match.group(1).strip()\r
393 self.Source = "DXS"\r
394 break\r
395 else:\r
396 self.Depex = M.DepexExpressionList.get(M.ModuleType, "")\r
397 self.ModuleDepex = " ".join(M.Module.DepexExpression[M.Arch, M.ModuleType])\r
398 if not self.ModuleDepex:\r
399 self.ModuleDepex = "(None)"\r
400\r
401 LibDepexList = []\r
402 for Lib in M.DependentLibraryList:\r
403 LibDepex = " ".join(Lib.DepexExpression[M.Arch, M.ModuleType]).strip()\r
404 if LibDepex != "":\r
405 LibDepexList.append("(" + LibDepex + ")")\r
406 self.LibraryDepex = " AND ".join(LibDepexList)\r
407 if not self.LibraryDepex:\r
408 self.LibraryDepex = "(None)"\r
409 self.Source = "INF"\r
410\r
411 ##\r
412 # Generate report for module dependency expression information\r
413 #\r
414 # This function generates report for the module dependency expression.\r
415 #\r
e56468c0 416 # @param self The object pointer\r
417 # @param File The file object for report\r
418 # @param GlobalDepexParser The platform global Dependency expression parser object\r
52302d4d 419 #\r
e56468c0 420 def GenerateReport(self, File, GlobalDepexParser):\r
52302d4d
LG
421 if not self.Depex:\r
422 return\r
52302d4d 423 FileWrite(File, gSubSectionStart)\r
e56468c0 424 if os.path.isfile(self._DepexFileName):\r
425 try:\r
426 DepexStatements = GlobalDepexParser.ParseDepexFile(self._DepexFileName)\r
427 FileWrite(File, "Final Dependency Expression (DEPEX) Instructions")\r
428 for DepexStatement in DepexStatements:\r
429 FileWrite(File, " %s" % DepexStatement)\r
430 FileWrite(File, gSubSectionSep)\r
431 except:\r
432 EdkLogger.warn(None, "Dependency expression file is corrupted", self._DepexFileName)\r
433 \r
52302d4d
LG
434 FileWrite(File, "Dependency Expression (DEPEX) from %s" % self.Source)\r
435\r
436 if self.Source == "INF":\r
437 FileWrite(File, "%s" % self.Depex, True)\r
438 FileWrite(File, gSubSectionSep)\r
439 FileWrite(File, "From Module INF: %s" % self.ModuleDepex, True)\r
440 FileWrite(File, "From Library INF: %s" % self.LibraryDepex, True)\r
441 else:\r
442 FileWrite(File, "%s" % self.Depex)\r
443 FileWrite(File, gSubSectionEnd)\r
444\r
445##\r
446# Reports dependency expression information\r
447#\r
448# This class reports the module build flags subsection in the build report file.\r
449#\r
450class BuildFlagsReport(object):\r
451 ##\r
452 # Constructor function for class BuildFlagsReport\r
453 #\r
454 # This constructor function generates BuildFlagsReport object for\r
455 # a module. It reports the build tool chain tag and all relevant\r
456 # build flags to build the module.\r
457 #\r
458 # @param self The object pointer\r
459 # @param M Module context information\r
460 #\r
461 def __init__(self, M):\r
462 BuildOptions = {}\r
463 #\r
464 # Add build flags according to source file extension so that\r
465 # irrelevant ones can be filtered out.\r
466 #\r
467 for Source in M.SourceFileList:\r
468 Ext = os.path.splitext(Source.File)[1].lower()\r
469 if Ext in [".c", ".cc", ".cpp"]:\r
470 BuildOptions["CC"] = 1\r
471 elif Ext in [".s", ".asm"]:\r
472 BuildOptions["PP"] = 1\r
473 BuildOptions["ASM"] = 1\r
474 elif Ext in [".vfr"]:\r
475 BuildOptions["VFRPP"] = 1\r
476 BuildOptions["VFR"] = 1\r
477 elif Ext in [".dxs"]:\r
478 BuildOptions["APP"] = 1\r
479 BuildOptions["CC"] = 1\r
480 elif Ext in [".asl"]:\r
481 BuildOptions["ASLPP"] = 1\r
482 BuildOptions["ASL"] = 1\r
483 elif Ext in [".aslc"]:\r
484 BuildOptions["ASLCC"] = 1\r
485 BuildOptions["ASLDLINK"] = 1\r
486 BuildOptions["CC"] = 1\r
487 elif Ext in [".asm16"]:\r
488 BuildOptions["ASMLINK"] = 1\r
489 BuildOptions["SLINK"] = 1\r
490 BuildOptions["DLINK"] = 1\r
491\r
492 #\r
493 # Save module build flags.\r
494 #\r
495 self.ToolChainTag = M.ToolChain\r
496 self.BuildFlags = {}\r
497 for Tool in BuildOptions:\r
498 self.BuildFlags[Tool + "_FLAGS"] = M.BuildOption.get(Tool, {}).get("FLAGS", "")\r
499\r
500 ##\r
501 # Generate report for module build flags information\r
502 #\r
503 # This function generates report for the module build flags expression.\r
504 #\r
505 # @param self The object pointer\r
506 # @param File The file object for report\r
507 #\r
508 def GenerateReport(self, File):\r
509 FileWrite(File, gSubSectionStart)\r
510 FileWrite(File, "Build Flags")\r
511 FileWrite(File, "Tool Chain Tag: %s" % self.ToolChainTag)\r
512 for Tool in self.BuildFlags:\r
513 FileWrite(File, gSubSectionSep)\r
514 FileWrite(File, "%s = %s" % (Tool, self.BuildFlags[Tool]), True)\r
515\r
516 FileWrite(File, gSubSectionEnd)\r
517\r
518\r
519##\r
520# Reports individual module information\r
521#\r
522# This class reports the module section in the build report file.\r
523# It comprises of module summary, module PCD, library, dependency expression,\r
524# build flags sections.\r
525#\r
526class ModuleReport(object):\r
527 ##\r
528 # Constructor function for class ModuleReport\r
529 #\r
530 # This constructor function generates ModuleReport object for\r
531 # a separate module in a platform build.\r
532 #\r
533 # @param self The object pointer\r
534 # @param M Module context information\r
535 # @param ReportType The kind of report items in the final report file\r
536 #\r
537 def __init__(self, M, ReportType):\r
538 self.ModuleName = M.Module.BaseName\r
539 self.ModuleInfPath = M.MetaFile.File\r
540 self.FileGuid = M.Guid\r
541 self.Size = 0\r
542 self.BuildTimeStamp = None\r
eca5be7a 543 self.Hash = 0\r
52302d4d 544 self.DriverType = ""\r
636f2be6
LG
545 if not M.IsLibrary:\r
546 ModuleType = M.ModuleType\r
547 if not ModuleType:\r
548 ModuleType = gComponentType2ModuleType.get(M.ComponentType, "")\r
549 #\r
550 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"\r
551 #\r
552 if ModuleType == "DXE_SMM_DRIVER":\r
47fea6af 553 PiSpec = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "0x00010000")\r
0d2711a6 554 if int(PiSpec, 0) >= 0x0001000A:\r
636f2be6
LG
555 ModuleType = "SMM_DRIVER"\r
556 self.DriverType = gDriverTypeMap.get(ModuleType, "0x2 (FREE_FORM)")\r
52302d4d
LG
557 self.UefiSpecVersion = M.Module.Specification.get("UEFI_SPECIFICATION_VERSION", "")\r
558 self.PiSpecVersion = M.Module.Specification.get("PI_SPECIFICATION_VERSION", "")\r
559 self.PciDeviceId = M.Module.Defines.get("PCI_DEVICE_ID", "")\r
560 self.PciVendorId = M.Module.Defines.get("PCI_VENDOR_ID", "")\r
561 self.PciClassCode = M.Module.Defines.get("PCI_CLASS_CODE", "")\r
1b8eca8b 562 self.BuildTime = M.BuildTime\r
52302d4d
LG
563\r
564 self._BuildDir = M.BuildDir\r
565 self.ModulePcdSet = {}\r
566 if "PCD" in ReportType:\r
567 #\r
568 # Collect all module used PCD set: module INF referenced directly or indirectly.\r
569 # It also saves module INF default values of them in case they exist.\r
570 #\r
571 for Pcd in M.ModulePcdList + M.LibraryPcdList:\r
572 self.ModulePcdSet.setdefault((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Type), (Pcd.InfDefaultValue, Pcd.DefaultValue))\r
573\r
574 self.LibraryReport = None\r
575 if "LIBRARY" in ReportType:\r
576 self.LibraryReport = LibraryReport(M)\r
577\r
578 self.DepexReport = None\r
579 if "DEPEX" in ReportType:\r
580 self.DepexReport = DepexReport(M)\r
581\r
582 if "BUILD_FLAGS" in ReportType:\r
583 self.BuildFlagsReport = BuildFlagsReport(M)\r
584\r
585\r
586 ##\r
587 # Generate report for module information\r
588 #\r
589 # This function generates report for separate module expression\r
590 # in a platform build.\r
591 #\r
e56468c0 592 # @param self The object pointer\r
593 # @param File The file object for report\r
594 # @param GlobalPcdReport The platform global PCD report object\r
595 # @param GlobalPredictionReport The platform global Prediction report object\r
596 # @param GlobalDepexParser The platform global Dependency expression parser object\r
597 # @param ReportType The kind of report items in the final report file\r
52302d4d 598 #\r
e56468c0 599 def GenerateReport(self, File, GlobalPcdReport, GlobalPredictionReport, GlobalDepexParser, ReportType):\r
52302d4d
LG
600 FileWrite(File, gSectionStart)\r
601\r
602 FwReportFileName = os.path.join(self._BuildDir, "DEBUG", self.ModuleName + ".txt")\r
603 if os.path.isfile(FwReportFileName):\r
604 try:\r
605 FileContents = open(FwReportFileName).read()\r
606 Match = gModuleSizePattern.search(FileContents)\r
607 if Match:\r
608 self.Size = int(Match.group(1))\r
609\r
610 Match = gTimeStampPattern.search(FileContents)\r
611 if Match:\r
612 self.BuildTimeStamp = datetime.fromtimestamp(int(Match.group(1)))\r
613 except IOError:\r
614 EdkLogger.warn(None, "Fail to read report file", FwReportFileName)\r
615\r
eca5be7a
YZ
616 if "HASH" in ReportType:\r
617 OutputDir = os.path.join(self._BuildDir, "OUTPUT")\r
618 DefaultEFIfile = os.path.join(OutputDir, self.ModuleName + ".efi")\r
619 if os.path.isfile(DefaultEFIfile):\r
620 Tempfile = os.path.join(OutputDir, self.ModuleName + "_hash.tmp")\r
621 # rebase the efi image since its base address may not zero\r
622 cmd = ["GenFw", "--rebase", str(0), "-o", Tempfile, DefaultEFIfile]\r
623 try:\r
624 PopenObject = subprocess.Popen(' '.join(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)\r
625 except Exception, X:\r
626 EdkLogger.error("GenFw", COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0]))\r
627 EndOfProcedure = threading.Event()\r
628 EndOfProcedure.clear()\r
629 if PopenObject.stderr:\r
630 StdErrThread = threading.Thread(target=ReadMessage, args=(PopenObject.stderr, EdkLogger.quiet, EndOfProcedure))\r
631 StdErrThread.setName("STDERR-Redirector")\r
632 StdErrThread.setDaemon(False)\r
633 StdErrThread.start()\r
634 # waiting for program exit\r
635 PopenObject.wait()\r
636 if PopenObject.stderr:\r
637 StdErrThread.join()\r
638 if PopenObject.returncode != 0:\r
639 EdkLogger.error("GenFw", COMMAND_FAILURE, "Failed to generate firmware hash image for %s" % (DefaultEFIfile))\r
640 if os.path.isfile(Tempfile):\r
641 self.Hash = hashlib.sha1()\r
642 buf = open(Tempfile, 'rb').read()\r
643 if self.Hash.update(buf):\r
644 self.Hash = self.Hash.update(buf)\r
645 self.Hash = self.Hash.hexdigest()\r
646 os.remove(Tempfile)\r
647\r
52302d4d
LG
648 FileWrite(File, "Module Summary")\r
649 FileWrite(File, "Module Name: %s" % self.ModuleName)\r
650 FileWrite(File, "Module INF Path: %s" % self.ModuleInfPath)\r
651 FileWrite(File, "File GUID: %s" % self.FileGuid)\r
652 if self.Size:\r
653 FileWrite(File, "Size: 0x%X (%.2fK)" % (self.Size, self.Size / 1024.0))\r
eca5be7a
YZ
654 if self.Hash:\r
655 FileWrite(File, "SHA1 HASH: %s *%s" % (self.Hash, self.ModuleName + ".efi"))\r
52302d4d
LG
656 if self.BuildTimeStamp:\r
657 FileWrite(File, "Build Time Stamp: %s" % self.BuildTimeStamp)\r
1b8eca8b
YZ
658 if self.BuildTime:\r
659 FileWrite(File, "Module Build Time: %s" % self.BuildTime)\r
52302d4d
LG
660 if self.DriverType:\r
661 FileWrite(File, "Driver Type: %s" % self.DriverType)\r
662 if self.UefiSpecVersion:\r
663 FileWrite(File, "UEFI Spec Version: %s" % self.UefiSpecVersion)\r
664 if self.PiSpecVersion:\r
665 FileWrite(File, "PI Spec Version: %s" % self.PiSpecVersion)\r
666 if self.PciDeviceId:\r
667 FileWrite(File, "PCI Device ID: %s" % self.PciDeviceId)\r
668 if self.PciVendorId:\r
669 FileWrite(File, "PCI Vendor ID: %s" % self.PciVendorId)\r
670 if self.PciClassCode:\r
671 FileWrite(File, "PCI Class Code: %s" % self.PciClassCode)\r
672\r
673 FileWrite(File, gSectionSep)\r
674\r
675 if "PCD" in ReportType:\r
676 GlobalPcdReport.GenerateReport(File, self.ModulePcdSet)\r
677\r
678 if "LIBRARY" in ReportType:\r
679 self.LibraryReport.GenerateReport(File)\r
680\r
681 if "DEPEX" in ReportType:\r
e56468c0 682 self.DepexReport.GenerateReport(File, GlobalDepexParser)\r
52302d4d
LG
683\r
684 if "BUILD_FLAGS" in ReportType:\r
685 self.BuildFlagsReport.GenerateReport(File)\r
686\r
687 if "FIXED_ADDRESS" in ReportType and self.FileGuid:\r
688 GlobalPredictionReport.GenerateReport(File, self.FileGuid)\r
689\r
690 FileWrite(File, gSectionEnd)\r
691\r
eca5be7a
YZ
692def ReadMessage(From, To, ExitFlag):\r
693 while True:\r
694 # read one line a time\r
695 Line = From.readline()\r
696 # empty string means "end"\r
697 if Line != None and Line != "":\r
698 To(Line.rstrip())\r
699 else:\r
700 break\r
701 if ExitFlag.isSet():\r
702 break\r
703\r
52302d4d
LG
704##\r
705# Reports platform and module PCD information\r
706#\r
707# This class reports the platform PCD section and module PCD subsection\r
708# in the build report file.\r
709#\r
710class PcdReport(object):\r
711 ##\r
712 # Constructor function for class PcdReport\r
713 #\r
714 # This constructor function generates PcdReport object a platform build.\r
715 # It collects the whole PCD database from platform DSC files, platform\r
716 # flash description file and package DEC files.\r
717 #\r
718 # @param self The object pointer\r
719 # @param Wa Workspace context information\r
720 #\r
721 def __init__(self, Wa):\r
722 self.AllPcds = {}\r
c8d07c5e
YZ
723 self.UnusedPcds = {}\r
724 self.ConditionalPcds = {}\r
52302d4d
LG
725 self.MaxLen = 0\r
726 if Wa.FdfProfile:\r
727 self.FdfPcdSet = Wa.FdfProfile.PcdDict\r
728 else:\r
729 self.FdfPcdSet = {}\r
730\r
731 self.ModulePcdOverride = {}\r
732 for Pa in Wa.AutoGenObjectList:\r
733 #\r
734 # Collect all platform referenced PCDs and grouped them by PCD token space\r
735 # GUID C Names\r
736 #\r
737 for Pcd in Pa.AllPcdList:\r
738 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
739 if Pcd not in PcdList:\r
740 PcdList.append(Pcd)\r
741 if len(Pcd.TokenCName) > self.MaxLen:\r
742 self.MaxLen = len(Pcd.TokenCName)\r
c8d07c5e
YZ
743 #\r
744 # Collect the PCD defined in DSC/FDF file, but not used in module\r
745 #\r
746 UnusedPcdFullList = []\r
747 for item in Pa.Platform.Pcds:\r
748 Pcd = Pa.Platform.Pcds[item]\r
c65df5d9
YZ
749 if not Pcd.Type:\r
750 # check the Pcd in FDF file, whether it is used in module first\r
751 for T in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]:\r
752 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(T, [])\r
753 if Pcd in PcdList:\r
754 Pcd.Type = T\r
755 break\r
c8d07c5e
YZ
756 if not Pcd.Type:\r
757 PcdTypeFlag = False\r
758 for package in Pa.PackageList:\r
759 for T in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]:\r
760 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T) in package.Pcds:\r
761 Pcd.Type = T\r
762 PcdTypeFlag = True\r
763 if not Pcd.DatumType:\r
764 Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, T)].DatumType\r
765 break\r
766 if PcdTypeFlag:\r
767 break\r
768 if not Pcd.DatumType:\r
769 PcdType = Pcd.Type\r
770 # Try to remove Hii and Vpd suffix\r
771 if PcdType.startswith("DynamicEx"):\r
772 PcdType = "DynamicEx"\r
773 elif PcdType.startswith("Dynamic"):\r
774 PcdType = "Dynamic"\r
775 for package in Pa.PackageList:\r
776 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType) in package.Pcds:\r
777 Pcd.DatumType = package.Pcds[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName, PcdType)].DatumType\r
778 break\r
779\r
780 PcdList = self.AllPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
781 if Pcd not in PcdList and Pcd not in UnusedPcdFullList:\r
782 UnusedPcdFullList.append(Pcd)\r
783 if len(Pcd.TokenCName) > self.MaxLen:\r
784 self.MaxLen = len(Pcd.TokenCName)\r
785\r
786 if GlobalData.gConditionalPcds:\r
787 for PcdItem in GlobalData.gConditionalPcds:\r
788 if '.' in PcdItem:\r
789 (TokenSpaceGuidCName, TokenCName) = PcdItem.split('.')\r
790 if (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds.keys():\r
791 Pcd = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)]\r
792 PcdList = self.ConditionalPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
793 if Pcd not in PcdList:\r
794 PcdList.append(Pcd)\r
795\r
796 UnusedPcdList = []\r
797 if UnusedPcdFullList:\r
798 for Pcd in UnusedPcdFullList:\r
799 if Pcd.TokenSpaceGuidCName + '.' + Pcd.TokenCName in GlobalData.gConditionalPcds:\r
800 continue\r
801 UnusedPcdList.append(Pcd)\r
802\r
803 for Pcd in UnusedPcdList:\r
804 PcdList = self.UnusedPcds.setdefault(Pcd.TokenSpaceGuidCName, {}).setdefault(Pcd.Type, [])\r
805 if Pcd not in PcdList:\r
806 PcdList.append(Pcd)\r
52302d4d
LG
807\r
808 for Module in Pa.Platform.Modules.values():\r
809 #\r
810 # Collect module override PCDs\r
811 #\r
812 for ModulePcd in Module.M.ModulePcdList + Module.M.LibraryPcdList:\r
813 TokenCName = ModulePcd.TokenCName\r
814 TokenSpaceGuid = ModulePcd.TokenSpaceGuidCName\r
815 ModuleDefault = ModulePcd.DefaultValue\r
816 ModulePath = os.path.basename(Module.M.MetaFile.File)\r
817 self.ModulePcdOverride.setdefault((TokenCName, TokenSpaceGuid), {})[ModulePath] = ModuleDefault\r
818\r
819\r
820 #\r
821 # Collect PCD DEC default value.\r
822 #\r
823 self.DecPcdDefault = {}\r
0d2711a6
LG
824 for Pa in Wa.AutoGenObjectList:\r
825 for Package in Pa.PackageList:\r
826 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
827 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
828 self.DecPcdDefault.setdefault((TokenCName, TokenSpaceGuidCName, DecType), DecDefaultValue)\r
52302d4d
LG
829 #\r
830 # Collect PCDs defined in DSC common section\r
831 #\r
832 self.DscPcdDefault = {}\r
4afd3d04
LG
833 for Arch in Wa.ArchList:\r
834 Platform = Wa.BuildDatabase[Wa.MetaFile, Arch, Wa.BuildTarget, Wa.ToolChain]\r
52302d4d
LG
835 for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:\r
836 DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
40d841f6
LG
837 if DscDefaultValue:\r
838 self.DscPcdDefault[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
52302d4d 839\r
c8d07c5e
YZ
840 def GenerateReport(self, File, ModulePcdSet):\r
841 if self.ConditionalPcds:\r
842 self.GenerateReportDetail(File, ModulePcdSet, 1)\r
843 if self.UnusedPcds:\r
844 self.GenerateReportDetail(File, ModulePcdSet, 2)\r
845 self.GenerateReportDetail(File, ModulePcdSet)\r
846\r
52302d4d
LG
847 ##\r
848 # Generate report for PCD information\r
849 #\r
850 # This function generates report for separate module expression\r
851 # in a platform build.\r
852 #\r
853 # @param self The object pointer\r
854 # @param File The file object for report\r
855 # @param ModulePcdSet Set of all PCDs referenced by module or None for\r
856 # platform PCD report\r
c8d07c5e
YZ
857 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional\r
858 # directives section report, 2 means Unused Pcds section report\r
52302d4d
LG
859 # @param DscOverridePcds Module DSC override PCDs set\r
860 #\r
c8d07c5e
YZ
861 def GenerateReportDetail(self, File, ModulePcdSet, ReportSubType = 0):\r
862 PcdDict = self.AllPcds\r
863 if ReportSubType == 1:\r
864 PcdDict = self.ConditionalPcds\r
865 elif ReportSubType == 2:\r
866 PcdDict = self.UnusedPcds\r
867\r
52302d4d 868 if ModulePcdSet == None:\r
52302d4d 869 FileWrite(File, gSectionStart)\r
c8d07c5e
YZ
870 if ReportSubType == 1:\r
871 FileWrite(File, "Conditional Directives used by the build system")\r
872 elif ReportSubType == 2:\r
873 FileWrite(File, "PCDs not used by modules or in conditional directives")\r
874 else:\r
875 FileWrite(File, "Platform Configuration Database Report")\r
876\r
763e8edf 877 FileWrite(File, " *B - PCD override in the build option")\r
52302d4d
LG
878 FileWrite(File, " *P - Platform scoped PCD override in DSC file")\r
879 FileWrite(File, " *F - Platform scoped PCD override in FDF file")\r
c8d07c5e
YZ
880 if not ReportSubType:\r
881 FileWrite(File, " *M - Module scoped PCD override")\r
52302d4d
LG
882 FileWrite(File, gSectionSep)\r
883 else:\r
c2d0a1f6 884 if not ReportSubType and ModulePcdSet:\r
c8d07c5e
YZ
885 #\r
886 # For module PCD sub-section\r
887 #\r
888 FileWrite(File, gSubSectionStart)\r
889 FileWrite(File, TAB_BRG_PCD)\r
890 FileWrite(File, gSubSectionSep)\r
52302d4d 891\r
c8d07c5e 892 for Key in PcdDict:\r
52302d4d
LG
893 #\r
894 # Group PCD by their token space GUID C Name\r
895 #\r
896 First = True\r
c8d07c5e 897 for Type in PcdDict[Key]:\r
52302d4d
LG
898 #\r
899 # Group PCD by their usage type\r
900 #\r
901 TypeName, DecType = gPcdTypeMap.get(Type, ("", Type))\r
c8d07c5e 902 for Pcd in PcdDict[Key][Type]:\r
7cb63c87
YZ
903 PcdTokenCName = Pcd.TokenCName\r
904 MixedPcdFlag = False\r
905 if GlobalData.MixedPcd:\r
906 for PcdKey in GlobalData.MixedPcd:\r
907 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdKey]:\r
908 PcdTokenCName = PcdKey[0]\r
909 MixedPcdFlag = True\r
910 if MixedPcdFlag and not ModulePcdSet:\r
911 continue\r
52302d4d
LG
912 #\r
913 # Get PCD default value and their override relationship\r
914 #\r
915 DecDefaultValue = self.DecPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, DecType))\r
916 DscDefaultValue = self.DscPcdDefault.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))\r
917 DscDefaultValue = self.FdfPcdSet.get((Pcd.TokenCName, Key), DscDefaultValue)\r
918 InfDefaultValue = None\r
919 \r
920 PcdValue = DecDefaultValue\r
921 if DscDefaultValue:\r
922 PcdValue = DscDefaultValue\r
923 if ModulePcdSet != None:\r
924 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type) not in ModulePcdSet:\r
925 continue\r
926 InfDefault, PcdValue = ModulePcdSet[Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Type]\r
927 if InfDefault == "":\r
928 InfDefault = None\r
763e8edf
YZ
929\r
930 BuildOptionMatch = False\r
931 if GlobalData.BuildOptionPcd:\r
932 for pcd in GlobalData.BuildOptionPcd:\r
933 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) == (pcd[0], pcd[1]):\r
934 PcdValue = pcd[2]\r
935 BuildOptionMatch = True\r
936 break\r
937\r
52302d4d
LG
938 if First:\r
939 if ModulePcdSet == None:\r
940 FileWrite(File, "")\r
941 FileWrite(File, Key)\r
942 First = False\r
943\r
944\r
945 if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):\r
946 PcdValueNumber = int(PcdValue.strip(), 0)\r
947 if DecDefaultValue == None:\r
948 DecMatch = True\r
949 else:\r
950 DecDefaultValueNumber = int(DecDefaultValue.strip(), 0)\r
951 DecMatch = (DecDefaultValueNumber == PcdValueNumber)\r
952\r
953 if InfDefaultValue == None:\r
954 InfMatch = True\r
955 else:\r
956 InfDefaultValueNumber = int(InfDefaultValue.strip(), 0)\r
957 InfMatch = (InfDefaultValueNumber == PcdValueNumber)\r
958\r
959 if DscDefaultValue == None:\r
960 DscMatch = True\r
961 else:\r
962 DscDefaultValueNumber = int(DscDefaultValue.strip(), 0)\r
963 DscMatch = (DscDefaultValueNumber == PcdValueNumber)\r
964 else:\r
965 if DecDefaultValue == None:\r
966 DecMatch = True\r
967 else:\r
d5d56f1b 968 DecMatch = (DecDefaultValue.strip() == PcdValue.strip())\r
52302d4d
LG
969\r
970 if InfDefaultValue == None:\r
971 InfMatch = True\r
972 else:\r
d5d56f1b 973 InfMatch = (InfDefaultValue.strip() == PcdValue.strip())\r
52302d4d
LG
974\r
975 if DscDefaultValue == None:\r
976 DscMatch = True\r
977 else:\r
d5d56f1b 978 DscMatch = (DscDefaultValue.strip() == PcdValue.strip())\r
52302d4d
LG
979\r
980 #\r
981 # Report PCD item according to their override relationship\r
982 #\r
0e6be43f 983 if DecMatch and InfMatch:\r
7cb63c87 984 FileWrite(File, ' %-*s: %6s %10s = %-22s' % (self.MaxLen, PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
0e6be43f
YZ
985 elif BuildOptionMatch:\r
986 FileWrite(File, ' *B %-*s: %6s %10s = %-22s' % (self.MaxLen, PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
52302d4d
LG
987 else:\r
988 if DscMatch:\r
989 if (Pcd.TokenCName, Key) in self.FdfPcdSet:\r
7cb63c87 990 FileWrite(File, ' *F %-*s: %6s %10s = %-22s' % (self.MaxLen, PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
52302d4d 991 else:\r
7cb63c87 992 FileWrite(File, ' *P %-*s: %6s %10s = %-22s' % (self.MaxLen, PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
52302d4d 993 else:\r
7cb63c87 994 FileWrite(File, ' *M %-*s: %6s %10s = %-22s' % (self.MaxLen, PcdTokenCName, TypeName, '(' + Pcd.DatumType + ')', PcdValue.strip()))\r
47fea6af 995\r
52302d4d
LG
996 if TypeName in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):\r
997 for SkuInfo in Pcd.SkuInfoList.values():\r
998 if TypeName in ('DYNHII', 'DEXHII'):\r
47fea6af 999 FileWrite(File, '%*s: %s: %s' % (self.MaxLen + 4, SkuInfo.VariableGuid, SkuInfo.VariableName, SkuInfo.VariableOffset))\r
52302d4d
LG
1000 else:\r
1001 FileWrite(File, '%*s' % (self.MaxLen + 4, SkuInfo.VpdOffset))\r
1002 \r
1003 if not DscMatch and DscDefaultValue != None:\r
d5d56f1b 1004 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DSC DEFAULT', DscDefaultValue.strip()))\r
52302d4d
LG
1005\r
1006 if not InfMatch and InfDefaultValue != None:\r
d5d56f1b 1007 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'INF DEFAULT', InfDefaultValue.strip()))\r
52302d4d
LG
1008\r
1009 if not DecMatch and DecDefaultValue != None:\r
d5d56f1b 1010 FileWrite(File, ' %*s = %s' % (self.MaxLen + 19, 'DEC DEFAULT', DecDefaultValue.strip()))\r
52302d4d
LG
1011\r
1012 if ModulePcdSet == None:\r
763e8edf
YZ
1013 if not BuildOptionMatch:\r
1014 ModuleOverride = self.ModulePcdOverride.get((Pcd.TokenCName, Pcd.TokenSpaceGuidCName), {})\r
1015 for ModulePath in ModuleOverride:\r
1016 ModuleDefault = ModuleOverride[ModulePath]\r
1017 if Pcd.DatumType in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):\r
1018 ModulePcdDefaultValueNumber = int(ModuleDefault.strip(), 0)\r
1019 Match = (ModulePcdDefaultValueNumber == PcdValueNumber)\r
1020 else:\r
1021 Match = (ModuleDefault.strip() == PcdValue.strip())\r
1022 if Match:\r
1023 continue\r
1024 FileWrite(File, ' *M %-*s = %s' % (self.MaxLen + 19, ModulePath, ModuleDefault.strip()))\r
52302d4d
LG
1025\r
1026 if ModulePcdSet == None:\r
1027 FileWrite(File, gSectionEnd)\r
1028 else:\r
c2d0a1f6 1029 if not ReportSubType and ModulePcdSet:\r
c8d07c5e 1030 FileWrite(File, gSubSectionEnd)\r
52302d4d
LG
1031\r
1032\r
1033\r
1034##\r
1035# Reports platform and module Prediction information\r
1036#\r
1037# This class reports the platform execution order prediction section and\r
1038# module load fixed address prediction subsection in the build report file.\r
1039#\r
1040class PredictionReport(object):\r
1041 ##\r
1042 # Constructor function for class PredictionReport\r
1043 #\r
1044 # This constructor function generates PredictionReport object for the platform.\r
1045 #\r
1046 # @param self: The object pointer\r
1047 # @param Wa Workspace context information\r
1048 #\r
1049 def __init__(self, Wa):\r
1050 self._MapFileName = os.path.join(Wa.BuildDir, Wa.Name + ".map")\r
1051 self._MapFileParsed = False\r
1052 self._EotToolInvoked = False\r
1053 self._FvDir = Wa.FvDir\r
1054 self._EotDir = Wa.BuildDir\r
1055 self._FfsEntryPoint = {}\r
1056 self._GuidMap = {}\r
1057 self._SourceList = []\r
1058 self.FixedMapDict = {}\r
1059 self.ItemList = []\r
1060 self.MaxLen = 0\r
1061\r
1062 #\r
1063 # Collect all platform reference source files and GUID C Name\r
1064 #\r
1065 for Pa in Wa.AutoGenObjectList:\r
1066 for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList:\r
1067 #\r
40d841f6
LG
1068 # BASE typed modules are EFI agnostic, so we need not scan\r
1069 # their source code to find PPI/Protocol produce or consume\r
1070 # information.\r
1071 #\r
1072 if Module.ModuleType == "BASE":\r
1073 continue\r
1074 #\r
52302d4d
LG
1075 # Add module referenced source files\r
1076 #\r
1077 self._SourceList.append(str(Module))\r
1078 IncludeList = {}\r
1079 for Source in Module.SourceFileList:\r
1080 if os.path.splitext(str(Source))[1].lower() == ".c":\r
1081 self._SourceList.append(" " + str(Source))\r
1082 FindIncludeFiles(Source.Path, Module.IncludePathList, IncludeList)\r
1083 for IncludeFile in IncludeList.values():\r
1084 self._SourceList.append(" " + IncludeFile)\r
1085\r
1086 for Guid in Module.PpiList:\r
1087 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.PpiList[Guid])\r
1088 for Guid in Module.ProtocolList:\r
1089 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.ProtocolList[Guid])\r
1090 for Guid in Module.GuidList:\r
1091 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.GuidList[Guid])\r
1092\r
1093 if Module.Guid and not Module.IsLibrary:\r
1094 EntryPoint = " ".join(Module.Module.ModuleEntryPointList)\r
1095 if int(str(Module.AutoGenVersion), 0) >= 0x00010005:\r
1096 RealEntryPoint = "_ModuleEntryPoint"\r
1097 else:\r
1098 RealEntryPoint = EntryPoint\r
1099 if EntryPoint == "_ModuleEntryPoint":\r
1100 CCFlags = Module.BuildOption.get("CC", {}).get("FLAGS", "")\r
1101 Match = gGlueLibEntryPoint.search(CCFlags)\r
1102 if Match:\r
1103 EntryPoint = Match.group(1)\r
1104\r
1105 self._FfsEntryPoint[Module.Guid.upper()] = (EntryPoint, RealEntryPoint)\r
1106\r
1107\r
1108 #\r
1109 # Collect platform firmware volume list as the input of EOT.\r
1110 #\r
1111 self._FvList = []\r
1112 if Wa.FdfProfile:\r
1113 for Fd in Wa.FdfProfile.FdDict:\r
1114 for FdRegion in Wa.FdfProfile.FdDict[Fd].RegionList:\r
1115 if FdRegion.RegionType != "FV":\r
1116 continue\r
1117 for FvName in FdRegion.RegionDataList:\r
1118 if FvName in self._FvList:\r
1119 continue\r
1120 self._FvList.append(FvName)\r
1121 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1122 for Section in Ffs.SectionList:\r
1123 try:\r
1124 for FvSection in Section.SectionList:\r
1125 if FvSection.FvName in self._FvList:\r
1126 continue\r
1127 self._FvList.append(FvSection.FvName)\r
1128 except AttributeError:\r
1129 pass\r
1130\r
1131\r
1132 ##\r
1133 # Parse platform fixed address map files\r
1134 #\r
1135 # This function parses the platform final fixed address map file to get\r
1136 # the database of predicted fixed address for module image base, entry point\r
1137 # etc.\r
1138 #\r
1139 # @param self: The object pointer\r
1140 #\r
1141 def _ParseMapFile(self):\r
1142 if self._MapFileParsed:\r
1143 return\r
1144 self._MapFileParsed = True\r
1145 if os.path.isfile(self._MapFileName):\r
1146 try:\r
1147 FileContents = open(self._MapFileName).read()\r
1148 for Match in gMapFileItemPattern.finditer(FileContents):\r
1149 AddressType = Match.group(1)\r
1150 BaseAddress = Match.group(2)\r
1151 EntryPoint = Match.group(3)\r
1152 Guid = Match.group(4).upper()\r
1153 List = self.FixedMapDict.setdefault(Guid, [])\r
1154 List.append((AddressType, BaseAddress, "*I"))\r
1155 List.append((AddressType, EntryPoint, "*E"))\r
1156 except:\r
1157 EdkLogger.warn(None, "Cannot open file to read", self._MapFileName)\r
1158\r
1159 ##\r
1160 # Invokes EOT tool to get the predicted the execution order.\r
1161 #\r
1162 # This function invokes EOT tool to calculate the predicted dispatch order\r
1163 #\r
1164 # @param self: The object pointer\r
1165 #\r
1166 def _InvokeEotTool(self):\r
1167 if self._EotToolInvoked:\r
1168 return\r
1169\r
1170 self._EotToolInvoked = True\r
1171 FvFileList = []\r
1172 for FvName in self._FvList:\r
1173 FvFile = os.path.join(self._FvDir, FvName + ".Fv")\r
1174 if os.path.isfile(FvFile):\r
1175 FvFileList.append(FvFile)\r
1176\r
1177 if len(FvFileList) == 0:\r
1178 return\r
1179 #\r
1180 # Write source file list and GUID file list to an intermediate file\r
1181 # as the input for EOT tool and dispatch List as the output file\r
1182 # from EOT tool.\r
1183 #\r
1184 SourceList = os.path.join(self._EotDir, "SourceFile.txt")\r
1185 GuidList = os.path.join(self._EotDir, "GuidList.txt")\r
1186 DispatchList = os.path.join(self._EotDir, "Dispatch.txt")\r
1187\r
1188 TempFile = open(SourceList, "w+")\r
1189 for Item in self._SourceList:\r
1190 FileWrite(TempFile, Item)\r
1191 TempFile.close()\r
1192 TempFile = open(GuidList, "w+")\r
1193 for Key in self._GuidMap:\r
1194 FileWrite(TempFile, "%s %s" % (Key, self._GuidMap[Key]))\r
1195 TempFile.close()\r
1196\r
1197 try:\r
1198 from Eot.Eot import Eot\r
40d841f6 1199\r
52302d4d 1200 #\r
40d841f6 1201 # Invoke EOT tool and echo its runtime performance\r
52302d4d 1202 #\r
40d841f6 1203 EotStartTime = time.time()\r
52302d4d
LG
1204 Eot(CommandLineOption=False, SourceFileList=SourceList, GuidList=GuidList,\r
1205 FvFileList=' '.join(FvFileList), Dispatch=DispatchList, IsInit=True)\r
40d841f6
LG
1206 EotEndTime = time.time()\r
1207 EotDuration = time.strftime("%H:%M:%S", time.gmtime(int(round(EotEndTime - EotStartTime))))\r
1208 EdkLogger.quiet("EOT run time: %s\n" % EotDuration)\r
1209 \r
52302d4d
LG
1210 #\r
1211 # Parse the output of EOT tool\r
1212 #\r
1213 for Line in open(DispatchList):\r
1214 if len(Line.split()) < 4:\r
1215 continue\r
1216 (Guid, Phase, FfsName, FilePath) = Line.split()\r
1217 Symbol = self._FfsEntryPoint.get(Guid, [FfsName, ""])[0]\r
1218 if len(Symbol) > self.MaxLen:\r
1219 self.MaxLen = len(Symbol)\r
1220 self.ItemList.append((Phase, Symbol, FilePath))\r
1221 except:\r
1222 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))\r
1223 EdkLogger.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")\r
1224\r
1225\r
1226 ##\r
1227 # Generate platform execution order report\r
1228 #\r
1229 # This function generates the predicted module execution order.\r
1230 #\r
1231 # @param self The object pointer\r
1232 # @param File The file object for report\r
1233 #\r
1234 def _GenerateExecutionOrderReport(self, File):\r
1235 self._InvokeEotTool()\r
1236 if len(self.ItemList) == 0:\r
1237 return\r
1238 FileWrite(File, gSectionStart)\r
1239 FileWrite(File, "Execution Order Prediction")\r
1240 FileWrite(File, "*P PEI phase")\r
1241 FileWrite(File, "*D DXE phase")\r
1242 FileWrite(File, "*E Module INF entry point name")\r
1243 FileWrite(File, "*N Module notification function name")\r
1244\r
1245 FileWrite(File, "Type %-*s %s" % (self.MaxLen, "Symbol", "Module INF Path"))\r
1246 FileWrite(File, gSectionSep)\r
1247 for Item in self.ItemList:\r
1248 FileWrite(File, "*%sE %-*s %s" % (Item[0], self.MaxLen, Item[1], Item[2]))\r
1249\r
1250 FileWrite(File, gSectionStart)\r
1251\r
1252 ##\r
1253 # Generate Fixed Address report.\r
1254 #\r
1255 # This function generate the predicted fixed address report for a module\r
1256 # specified by Guid.\r
1257 #\r
1258 # @param self The object pointer\r
1259 # @param File The file object for report\r
1260 # @param Guid The module Guid value.\r
1261 # @param NotifyList The list of all notify function in a module\r
1262 #\r
1263 def _GenerateFixedAddressReport(self, File, Guid, NotifyList):\r
1264 self._ParseMapFile()\r
1265 FixedAddressList = self.FixedMapDict.get(Guid)\r
1266 if not FixedAddressList:\r
1267 return\r
1268\r
1269 FileWrite(File, gSubSectionStart)\r
1270 FileWrite(File, "Fixed Address Prediction")\r
1271 FileWrite(File, "*I Image Loading Address")\r
1272 FileWrite(File, "*E Entry Point Address")\r
1273 FileWrite(File, "*N Notification Function Address")\r
1274 FileWrite(File, "*F Flash Address")\r
1275 FileWrite(File, "*M Memory Address")\r
1276 FileWrite(File, "*S SMM RAM Offset")\r
1277 FileWrite(File, "TOM Top of Memory")\r
1278\r
1279 FileWrite(File, "Type Address Name")\r
1280 FileWrite(File, gSubSectionSep)\r
1281 for Item in FixedAddressList:\r
1282 Type = Item[0]\r
1283 Value = Item[1]\r
1284 Symbol = Item[2]\r
1285 if Symbol == "*I":\r
1286 Name = "(Image Base)"\r
1287 elif Symbol == "*E":\r
1288 Name = self._FfsEntryPoint.get(Guid, ["", "_ModuleEntryPoint"])[1]\r
1289 elif Symbol in NotifyList:\r
1290 Name = Symbol\r
1291 Symbol = "*N"\r
1292 else:\r
1293 continue\r
1294\r
1295 if "Flash" in Type:\r
1296 Symbol += "F"\r
1297 elif "Memory" in Type:\r
1298 Symbol += "M"\r
1299 else:\r
1300 Symbol += "S"\r
1301\r
1302 if Value[0] == "-":\r
1303 Value = "TOM" + Value\r
1304\r
1305 FileWrite(File, "%s %-16s %s" % (Symbol, Value, Name))\r
1306\r
1307 ##\r
1308 # Generate report for the prediction part\r
1309 #\r
1310 # This function generate the predicted fixed address report for a module or\r
1311 # predicted module execution order for a platform.\r
1312 # If the input Guid is None, then, it generates the predicted module execution order;\r
1313 # otherwise it generated the module fixed loading address for the module specified by\r
1314 # Guid.\r
1315 #\r
1316 # @param self The object pointer\r
1317 # @param File The file object for report\r
1318 # @param Guid The module Guid value.\r
1319 #\r
1320 def GenerateReport(self, File, Guid):\r
1321 if Guid:\r
1322 self._GenerateFixedAddressReport(File, Guid.upper(), [])\r
1323 else:\r
1324 self._GenerateExecutionOrderReport(File)\r
1325\r
1326##\r
1327# Reports FD region information\r
1328#\r
1329# This class reports the FD subsection in the build report file.\r
1330# It collects region information of platform flash device.\r
1331# If the region is a firmware volume, it lists the set of modules\r
1332# and its space information; otherwise, it only lists its region name,\r
1333# base address and size in its sub-section header.\r
1334# If there are nesting FVs, the nested FVs will list immediate after\r
1335# this FD region subsection\r
1336#\r
1337class FdRegionReport(object):\r
1338 ##\r
1339 # Discover all the nested FV name list.\r
1340 #\r
1341 # This is an internal worker function to discover the all the nested FV information\r
1342 # in the parent firmware volume. It uses deep first search algorithm recursively to\r
1343 # find all the FV list name and append them to the list.\r
1344 #\r
1345 # @param self The object pointer\r
1346 # @param FvName The name of current firmware file system\r
1347 # @param Wa Workspace context information\r
1348 #\r
1349 def _DiscoverNestedFvList(self, FvName, Wa):\r
a2432972
EC
1350 FvDictKey=FvName.upper()\r
1351 if FvDictKey in Wa.FdfProfile.FvDict:\r
1352 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1353 for Section in Ffs.SectionList:\r
1354 try:\r
1355 for FvSection in Section.SectionList:\r
1356 if FvSection.FvName in self.FvList:\r
1357 continue\r
1358 self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName\r
1359 self.FvList.append(FvSection.FvName)\r
1360 self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0)\r
1361 self._DiscoverNestedFvList(FvSection.FvName, Wa)\r
1362 except AttributeError:\r
1363 pass\r
52302d4d
LG
1364\r
1365 ##\r
1366 # Constructor function for class FdRegionReport\r
1367 #\r
1368 # This constructor function generates FdRegionReport object for a specified FdRegion.\r
1369 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware\r
1370 # volume list. This function also collects GUID map in order to dump module identification\r
1371 # in the final report.\r
1372 #\r
1373 # @param self: The object pointer\r
1374 # @param FdRegion The current FdRegion object\r
1375 # @param Wa Workspace context information\r
1376 #\r
1377 def __init__(self, FdRegion, Wa):\r
1378 self.Type = FdRegion.RegionType\r
1379 self.BaseAddress = FdRegion.Offset\r
1380 self.Size = FdRegion.Size\r
1381 self.FvList = []\r
1382 self.FvInfo = {}\r
1383 self._GuidsDb = {}\r
1384 self._FvDir = Wa.FvDir\r
1385\r
1386 #\r
1387 # If the input FdRegion is not a firmware volume,\r
1388 # we are done.\r
1389 #\r
1390 if self.Type != "FV":\r
1391 return\r
1392\r
1393 #\r
1394 # Find all nested FVs in the FdRegion\r
1395 #\r
1396 for FvName in FdRegion.RegionDataList:\r
1397 if FvName in self.FvList:\r
1398 continue\r
1399 self.FvList.append(FvName)\r
1400 self.FvInfo[FvName] = ("Fd Region", self.BaseAddress, self.Size)\r
1401 self._DiscoverNestedFvList(FvName, Wa)\r
1402\r
1403 PlatformPcds = {}\r
52302d4d
LG
1404 #\r
1405 # Collect PCDs declared in DEC files.\r
0d2711a6
LG
1406 # \r
1407 for Pa in Wa.AutoGenObjectList:\r
1408 for Package in Pa.PackageList:\r
1409 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:\r
1410 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue\r
1411 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue\r
52302d4d 1412 #\r
af9785a9 1413 # Collect PCDs defined in DSC file\r
52302d4d 1414 #\r
af9785a9
YZ
1415 for arch in Wa.ArchList:\r
1416 Platform = Wa.BuildDatabase[Wa.MetaFile, arch]\r
1417 for (TokenCName, TokenSpaceGuidCName) in Platform.Pcds:\r
1418 DscDefaultValue = Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue\r
1419 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue\r
52302d4d
LG
1420\r
1421 #\r
1422 # Add PEI and DXE a priori files GUIDs defined in PI specification.\r
1423 #\r
1424 self._GuidsDb["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"\r
1425 self._GuidsDb["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"\r
1426 #\r
1427 # Add ACPI table storage file\r
1428 #\r
1429 self._GuidsDb["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"\r
1430\r
1431 for Pa in Wa.AutoGenObjectList:\r
1432 for ModuleKey in Pa.Platform.Modules:\r
1433 M = Pa.Platform.Modules[ModuleKey].M\r
05cc51ad 1434 InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File)\r
52302d4d
LG
1435 self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath)\r
1436\r
1437 #\r
1438 # Collect the GUID map in the FV firmware volume\r
1439 #\r
1440 for FvName in self.FvList:\r
a2432972
EC
1441 FvDictKey=FvName.upper()\r
1442 if FvDictKey in Wa.FdfProfile.FvDict:\r
1443 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:\r
1444 try:\r
1445 #\r
1446 # collect GUID map for binary EFI file in FDF file.\r
1447 #\r
1448 Guid = Ffs.NameGuid.upper()\r
1449 Match = gPcdGuidPattern.match(Ffs.NameGuid)\r
1450 if Match:\r
1451 PcdTokenspace = Match.group(1)\r
1452 PcdToken = Match.group(2)\r
1453 if (PcdToken, PcdTokenspace) in PlatformPcds:\r
1454 GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)]\r
1455 Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()\r
1456 for Section in Ffs.SectionList:\r
1457 try:\r
1458 ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName)\r
1459 self._GuidsDb[Guid] = ModuleSectFile\r
1460 except AttributeError:\r
1461 pass\r
1462 except AttributeError:\r
1463 pass\r
52302d4d
LG
1464\r
1465\r
1466 ##\r
1467 # Internal worker function to generate report for the FD region\r
1468 #\r
1469 # This internal worker function to generate report for the FD region.\r
1470 # It the type is firmware volume, it lists offset and module identification.\r
1471 #\r
1472 # @param self The object pointer\r
1473 # @param File The file object for report\r
1474 # @param Title The title for the FD subsection\r
1475 # @param BaseAddress The base address for the FD region\r
1476 # @param Size The size of the FD region\r
1477 # @param FvName The FV name if the FD region is a firmware volume\r
1478 #\r
1479 def _GenerateReport(self, File, Title, Type, BaseAddress, Size=0, FvName=None):\r
1480 FileWrite(File, gSubSectionStart)\r
1481 FileWrite(File, Title)\r
1482 FileWrite(File, "Type: %s" % Type)\r
1483 FileWrite(File, "Base Address: 0x%X" % BaseAddress)\r
1484\r
1485 if self.Type == "FV":\r
1486 FvTotalSize = 0\r
1487 FvTakenSize = 0\r
1488 FvFreeSize = 0\r
b36d134f 1489 FvReportFileName = os.path.join(self._FvDir, FvName + ".Fv.txt")\r
52302d4d
LG
1490 try:\r
1491 #\r
1492 # Collect size info in the firmware volume.\r
1493 #\r
1494 FvReport = open(FvReportFileName).read()\r
1495 Match = gFvTotalSizePattern.search(FvReport)\r
1496 if Match:\r
1497 FvTotalSize = int(Match.group(1), 16)\r
1498 Match = gFvTakenSizePattern.search(FvReport)\r
1499 if Match:\r
1500 FvTakenSize = int(Match.group(1), 16)\r
1501 FvFreeSize = FvTotalSize - FvTakenSize\r
1502 #\r
1503 # Write size information to the report file.\r
1504 #\r
1505 FileWrite(File, "Size: 0x%X (%.0fK)" % (FvTotalSize, FvTotalSize / 1024.0))\r
1506 FileWrite(File, "Fv Name: %s (%.1f%% Full)" % (FvName, FvTakenSize * 100.0 / FvTotalSize))\r
1507 FileWrite(File, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize, FvTakenSize / 1024.0))\r
1508 FileWrite(File, "Free Size: 0x%X (%.0fK)" % (FvFreeSize, FvFreeSize / 1024.0))\r
1509 FileWrite(File, "Offset Module")\r
1510 FileWrite(File, gSubSectionSep)\r
1511 #\r
1512 # Write module offset and module identification to the report file.\r
1513 #\r
1514 OffsetInfo = {}\r
1515 for Match in gOffsetGuidPattern.finditer(FvReport):\r
1516 Guid = Match.group(2).upper()\r
1517 OffsetInfo[Match.group(1)] = self._GuidsDb.get(Guid, Guid)\r
1518 OffsetList = OffsetInfo.keys()\r
1519 OffsetList.sort()\r
1520 for Offset in OffsetList:\r
1521 FileWrite (File, "%s %s" % (Offset, OffsetInfo[Offset]))\r
1522 except IOError:\r
1523 EdkLogger.warn(None, "Fail to read report file", FvReportFileName)\r
1524 else:\r
1525 FileWrite(File, "Size: 0x%X (%.0fK)" % (Size, Size / 1024.0))\r
1526 FileWrite(File, gSubSectionEnd)\r
1527\r
1528 ##\r
1529 # Generate report for the FD region\r
1530 #\r
1531 # This function generates report for the FD region.\r
1532 #\r
1533 # @param self The object pointer\r
1534 # @param File The file object for report\r
1535 #\r
1536 def GenerateReport(self, File):\r
1537 if (len(self.FvList) > 0):\r
1538 for FvItem in self.FvList:\r
1539 Info = self.FvInfo[FvItem]\r
1540 self._GenerateReport(File, Info[0], "FV", Info[1], Info[2], FvItem)\r
1541 else:\r
1542 self._GenerateReport(File, "FD Region", self.Type, self.BaseAddress, self.Size)\r
1543\r
1544##\r
1545# Reports FD information\r
1546#\r
1547# This class reports the FD section in the build report file.\r
1548# It collects flash device information for a platform.\r
1549#\r
1550class FdReport(object):\r
1551 ##\r
1552 # Constructor function for class FdReport\r
1553 #\r
1554 # This constructor function generates FdReport object for a specified\r
1555 # firmware device.\r
1556 #\r
1557 # @param self The object pointer\r
1558 # @param Fd The current Firmware device object\r
1559 # @param Wa Workspace context information\r
1560 #\r
1561 def __init__(self, Fd, Wa):\r
1562 self.FdName = Fd.FdUiName\r
1563 self.BaseAddress = Fd.BaseAddress\r
1564 self.Size = Fd.Size\r
1565 self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList]\r
fb3d2279
YZ
1566 self.FvPath = os.path.join(Wa.BuildDir, "FV")\r
1567 self.VpdFilePath = os.path.join(self.FvPath, "%s.map" % Wa.Platform.VpdToolGuid)\r
043928da
YZ
1568 self.VPDBaseAddress = 0\r
1569 self.VPDSize = 0\r
fb3d2279
YZ
1570 self.VPDInfoList = []\r
1571 for index, FdRegion in enumerate(Fd.RegionList):\r
043928da 1572 if str(FdRegion.RegionType) is 'FILE' and Wa.Platform.VpdToolGuid in str(FdRegion.RegionDataList):\r
fb3d2279
YZ
1573 self.VPDBaseAddress = self.FdRegionList[index].BaseAddress\r
1574 self.VPDSize = self.FdRegionList[index].Size\r
1575 break\r
1576\r
1577 if os.path.isfile(self.VpdFilePath):\r
1578 fd = open(self.VpdFilePath, "r")\r
1579 Lines = fd.readlines()\r
1580 for Line in Lines:\r
1581 Line = Line.strip()\r
1582 if len(Line) == 0 or Line.startswith("#"):\r
1583 continue\r
1584 try:\r
1585 PcdName, SkuId, Offset, Size, Value = Line.split("#")[0].split("|")\r
1586 PcdName, SkuId, Offset, Size, Value = PcdName.strip(), SkuId.strip(), Offset.strip(), Size.strip(), Value.strip()\r
8401d398
YZ
1587 if Offset.lower().startswith('0x'):\r
1588 Offset = '0x%08X' % (int(Offset, 16) + self.VPDBaseAddress)\r
1589 else:\r
1590 Offset = '0x%08X' % (int(Offset, 10) + self.VPDBaseAddress)\r
fb3d2279
YZ
1591 self.VPDInfoList.append("%s | %s | %s | %s | %s" % (PcdName, SkuId, Offset, Size, Value))\r
1592 except:\r
1593 EdkLogger.error("BuildReport", CODE_ERROR, "Fail to parse VPD information file %s" % self.VpdFilePath)\r
1594 fd.close()\r
52302d4d
LG
1595\r
1596 ##\r
1597 # Generate report for the firmware device.\r
1598 #\r
1599 # This function generates report for the firmware device.\r
1600 #\r
1601 # @param self The object pointer\r
1602 # @param File The file object for report\r
1603 #\r
1604 def GenerateReport(self, File):\r
1605 FileWrite(File, gSectionStart)\r
1606 FileWrite(File, "Firmware Device (FD)")\r
1607 FileWrite(File, "FD Name: %s" % self.FdName)\r
1608 FileWrite(File, "Base Address: %s" % self.BaseAddress)\r
1609 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.Size, self.Size / 1024.0))\r
1610 if len(self.FdRegionList) > 0:\r
1611 FileWrite(File, gSectionSep)\r
1612 for FdRegionItem in self.FdRegionList:\r
1613 FdRegionItem.GenerateReport(File)\r
1614\r
fb3d2279
YZ
1615 if len(self.VPDInfoList) > 0:\r
1616 FileWrite(File, gSubSectionStart)\r
1617 FileWrite(File, "FD VPD Region")\r
1618 FileWrite(File, "Base Address: 0x%X" % self.VPDBaseAddress)\r
1619 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.VPDSize, self.VPDSize / 1024.0))\r
1620 FileWrite(File, gSubSectionSep)\r
1621 for item in self.VPDInfoList:\r
1622 FileWrite(File, item)\r
1623 FileWrite(File, gSubSectionEnd)\r
52302d4d
LG
1624 FileWrite(File, gSectionEnd)\r
1625\r
1626\r
1627\r
1628##\r
1629# Reports platform information\r
1630#\r
1631# This class reports the whole platform information\r
1632#\r
1633class PlatformReport(object):\r
1634 ##\r
1635 # Constructor function for class PlatformReport\r
1636 #\r
1637 # This constructor function generates PlatformReport object a platform build.\r
1638 # It generates report for platform summary, flash, global PCDs and detailed\r
1639 # module information for modules involved in platform build.\r
1640 #\r
1641 # @param self The object pointer\r
1642 # @param Wa Workspace context information\r
d5d56f1b 1643 # @param MaList The list of modules in the platform build\r
52302d4d 1644 #\r
d5d56f1b 1645 def __init__(self, Wa, MaList, ReportType):\r
52302d4d
LG
1646 self._WorkspaceDir = Wa.WorkspaceDir\r
1647 self.PlatformName = Wa.Name\r
1648 self.PlatformDscPath = Wa.Platform\r
1649 self.Architectures = " ".join(Wa.ArchList)\r
1650 self.ToolChain = Wa.ToolChain\r
1651 self.Target = Wa.BuildTarget\r
1652 self.OutputPath = os.path.join(Wa.WorkspaceDir, Wa.OutputDir)\r
1653 self.BuildEnvironment = platform.platform()\r
1654\r
1655 self.PcdReport = None\r
1656 if "PCD" in ReportType:\r
1657 self.PcdReport = PcdReport(Wa)\r
1658\r
1659 self.FdReportList = []\r
d5d56f1b 1660 if "FLASH" in ReportType and Wa.FdfProfile and MaList == None:\r
52302d4d
LG
1661 for Fd in Wa.FdfProfile.FdDict:\r
1662 self.FdReportList.append(FdReport(Wa.FdfProfile.FdDict[Fd], Wa))\r
1663\r
1664 self.PredictionReport = None\r
1665 if "FIXED_ADDRESS" in ReportType or "EXECUTION_ORDER" in ReportType:\r
1666 self.PredictionReport = PredictionReport(Wa)\r
1667\r
e56468c0 1668 self.DepexParser = None\r
1669 if "DEPEX" in ReportType:\r
1670 self.DepexParser = DepexParser(Wa)\r
1671 \r
52302d4d 1672 self.ModuleReportList = []\r
d5d56f1b 1673 if MaList != None:\r
636f2be6 1674 self._IsModuleBuild = True\r
d5d56f1b
LG
1675 for Ma in MaList:\r
1676 self.ModuleReportList.append(ModuleReport(Ma, ReportType))\r
1677 else:\r
636f2be6 1678 self._IsModuleBuild = False\r
d5d56f1b 1679 for Pa in Wa.AutoGenObjectList:\r
25193a33 1680 ModuleAutoGenList = []\r
d5d56f1b 1681 for ModuleKey in Pa.Platform.Modules:\r
25193a33
YZ
1682 ModuleAutoGenList.append(Pa.Platform.Modules[ModuleKey].M)\r
1683 if GlobalData.gFdfParser != None:\r
1684 if Pa.Arch in GlobalData.gFdfParser.Profile.InfDict:\r
1685 INFList = GlobalData.gFdfParser.Profile.InfDict[Pa.Arch]\r
1686 for InfName in INFList:\r
1687 InfClass = PathClass(NormPath(InfName), Wa.WorkspaceDir, Pa.Arch)\r
1688 Ma = ModuleAutoGen(Wa, InfClass, Pa.BuildTarget, Pa.ToolChain, Pa.Arch, Wa.MetaFile)\r
1689 if Ma == None:\r
1690 continue\r
1691 if Ma not in ModuleAutoGenList:\r
1692 ModuleAutoGenList.append(Ma)\r
1693 for MGen in ModuleAutoGenList:\r
1694 self.ModuleReportList.append(ModuleReport(MGen, ReportType))\r
52302d4d
LG
1695\r
1696\r
1697\r
1698 ##\r
1699 # Generate report for the whole platform.\r
1700 #\r
1701 # This function generates report for platform information.\r
1702 # It comprises of platform summary, global PCD, flash and\r
1703 # module list sections.\r
1704 #\r
1705 # @param self The object pointer\r
1706 # @param File The file object for report\r
1707 # @param BuildDuration The total time to build the modules\r
1b8eca8b
YZ
1708 # @param AutoGenTime The total time of AutoGen Phase\r
1709 # @param MakeTime The total time of Make Phase\r
1710 # @param GenFdsTime The total time of GenFds Phase\r
52302d4d
LG
1711 # @param ReportType The kind of report items in the final report file\r
1712 #\r
1b8eca8b 1713 def GenerateReport(self, File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, ReportType):\r
52302d4d
LG
1714 FileWrite(File, "Platform Summary")\r
1715 FileWrite(File, "Platform Name: %s" % self.PlatformName)\r
1716 FileWrite(File, "Platform DSC Path: %s" % self.PlatformDscPath)\r
1717 FileWrite(File, "Architectures: %s" % self.Architectures)\r
1718 FileWrite(File, "Tool Chain: %s" % self.ToolChain)\r
1719 FileWrite(File, "Target: %s" % self.Target)\r
1720 FileWrite(File, "Output Path: %s" % self.OutputPath)\r
1721 FileWrite(File, "Build Environment: %s" % self.BuildEnvironment)\r
1722 FileWrite(File, "Build Duration: %s" % BuildDuration)\r
1b8eca8b
YZ
1723 if AutoGenTime:\r
1724 FileWrite(File, "AutoGen Duration: %s" % AutoGenTime)\r
1725 if MakeTime:\r
1726 FileWrite(File, "Make Duration: %s" % MakeTime)\r
1727 if GenFdsTime:\r
1728 FileWrite(File, "GenFds Duration: %s" % GenFdsTime)\r
52302d4d
LG
1729 FileWrite(File, "Report Content: %s" % ", ".join(ReportType))\r
1730\r
2a29017e
YZ
1731 if GlobalData.MixedPcd:\r
1732 FileWrite(File, gSectionStart)\r
1733 FileWrite(File, "The following PCDs use different access methods:")\r
1734 FileWrite(File, gSectionSep)\r
1735 for PcdItem in GlobalData.MixedPcd:\r
1736 FileWrite(File, "%s.%s" % (str(PcdItem[1]), str(PcdItem[0])))\r
1737 FileWrite(File, gSectionEnd)\r
1738\r
636f2be6
LG
1739 if not self._IsModuleBuild:\r
1740 if "PCD" in ReportType:\r
1741 self.PcdReport.GenerateReport(File, None)\r
1742 \r
1743 if "FLASH" in ReportType:\r
1744 for FdReportListItem in self.FdReportList:\r
1745 FdReportListItem.GenerateReport(File)\r
52302d4d
LG
1746\r
1747 for ModuleReportItem in self.ModuleReportList:\r
e56468c0 1748 ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, self.DepexParser, ReportType)\r
52302d4d 1749\r
636f2be6
LG
1750 if not self._IsModuleBuild:\r
1751 if "EXECUTION_ORDER" in ReportType:\r
1752 self.PredictionReport.GenerateReport(File, None)\r
52302d4d
LG
1753\r
1754## BuildReport class\r
1755#\r
1756# This base class contain the routines to collect data and then\r
1757# applies certain format to the output report\r
1758#\r
1759class BuildReport(object):\r
1760 ##\r
1761 # Constructor function for class BuildReport\r
1762 #\r
1763 # This constructor function generates BuildReport object a platform build.\r
1764 # It generates report for platform summary, flash, global PCDs and detailed\r
1765 # module information for modules involved in platform build.\r
1766 #\r
1767 # @param self The object pointer\r
1768 # @param ReportFile The file name to save report file\r
1769 # @param ReportType The kind of report items in the final report file\r
1770 #\r
1771 def __init__(self, ReportFile, ReportType):\r
1772 self.ReportFile = ReportFile\r
1773 if ReportFile:\r
1774 self.ReportList = []\r
1775 self.ReportType = []\r
1776 if ReportType: \r
1777 for ReportTypeItem in ReportType:\r
1778 if ReportTypeItem not in self.ReportType:\r
1779 self.ReportType.append(ReportTypeItem)\r
1780 else:\r
eca5be7a 1781 self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]\r
52302d4d
LG
1782 ##\r
1783 # Adds platform report to the list\r
1784 #\r
1785 # This function adds a platform report to the final report list.\r
1786 #\r
1787 # @param self The object pointer\r
1788 # @param Wa Workspace context information\r
d5d56f1b 1789 # @param MaList The list of modules in the platform build\r
52302d4d 1790 #\r
d5d56f1b 1791 def AddPlatformReport(self, Wa, MaList=None):\r
52302d4d 1792 if self.ReportFile:\r
d5d56f1b 1793 self.ReportList.append((Wa, MaList))\r
52302d4d
LG
1794\r
1795 ##\r
1796 # Generates the final report.\r
1797 #\r
1798 # This function generates platform build report. It invokes GenerateReport()\r
1799 # method for every platform report in the list.\r
1800 #\r
1801 # @param self The object pointer\r
1802 # @param BuildDuration The total time to build the modules\r
1b8eca8b
YZ
1803 # @param AutoGenTime The total time of AutoGen phase\r
1804 # @param MakeTime The total time of Make phase\r
1805 # @param GenFdsTime The total time of GenFds phase\r
52302d4d 1806 #\r
1b8eca8b 1807 def GenerateReport(self, BuildDuration, AutoGenTime, MakeTime, GenFdsTime):\r
52302d4d
LG
1808 if self.ReportFile:\r
1809 try:\r
40d841f6 1810 File = StringIO('')\r
d5d56f1b 1811 for (Wa, MaList) in self.ReportList:\r
1b8eca8b 1812 PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, self.ReportType)\r
64b2609f
LG
1813 Content = FileLinesSplit(File.getvalue(), gLineMaxLength)\r
1814 SaveFileOnChange(self.ReportFile, Content, True)\r
40d841f6 1815 EdkLogger.quiet("Build report can be found at %s" % os.path.abspath(self.ReportFile))\r
52302d4d
LG
1816 except IOError:\r
1817 EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)\r
1818 except:\r
1819 EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report", ExtraData=self.ReportFile, RaiseError=False)\r
1820 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))\r
1821 File.close()\r
636f2be6 1822 \r
52302d4d
LG
1823# This acts like the main() function for the script, unless it is 'import'ed into another script.\r
1824if __name__ == '__main__':\r
1825 pass\r
1826\r