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