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