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