]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/build/BuildReport.py
BaseTools: AutoGen and GenFds share the parser data.
[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 Key, Values in OverrideStruct.items():
1428 if Values[1] and Values[1].endswith('.dsc'):
1429 OverrideFieldStruct[Key] = Values
1430 if Pcd.PcdFieldValueFromFdf:
1431 for Key, Values in Pcd.PcdFieldValueFromFdf.items():
1432 if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:
1433 continue
1434 OverrideFieldStruct[Key] = Values
1435 if Pcd.PcdFieldValueFromComm:
1436 for Key, Values in Pcd.PcdFieldValueFromComm.items():
1437 if Key in OverrideFieldStruct and Values[0] == OverrideFieldStruct[Key][0]:
1438 continue
1439 OverrideFieldStruct[Key] = Values
1440 return OverrideFieldStruct
1441
1442 def PrintStructureInfo(self, File, Struct):
1443 for Key, Value in sorted(Struct.items(), key=lambda x: x[0]):
1444 if Value[1] and 'build command options' in Value[1]:
1445 FileWrite(File, ' *B %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
1446 elif Value[1] and Value[1].endswith('.fdf'):
1447 FileWrite(File, ' *F %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
1448 else:
1449 FileWrite(File, ' %-*s = %s' % (self.MaxLen + 4, '.' + Key, Value[0]))
1450
1451 def StrtoHex(self, value):
1452 try:
1453 value = hex(int(value))
1454 return value
1455 except:
1456 if value.startswith("L\"") and value.endswith("\""):
1457 valuelist = []
1458 for ch in value[2:-1]:
1459 valuelist.append(hex(ord(ch)))
1460 valuelist.append('0x00')
1461 return valuelist
1462 elif value.startswith("\"") and value.endswith("\""):
1463 return hex(ord(value[1:-1]))
1464 elif value.startswith("{") and value.endswith("}"):
1465 valuelist = []
1466 if ',' not in value:
1467 return value[1:-1]
1468 for ch in value[1:-1].split(','):
1469 ch = ch.strip()
1470 if ch.startswith('0x') or ch.startswith('0X'):
1471 valuelist.append(ch)
1472 continue
1473 try:
1474 valuelist.append(hex(int(ch.strip())))
1475 except:
1476 pass
1477 return valuelist
1478 else:
1479 return value
1480
1481 def IsStructurePcd(self, PcdToken, PcdTokenSpaceGuid):
1482 if GlobalData.gStructurePcd and (self.Arch in GlobalData.gStructurePcd) and ((PcdToken, PcdTokenSpaceGuid) in GlobalData.gStructurePcd[self.Arch]):
1483 return True
1484 else:
1485 return False
1486
1487 ##
1488 # Reports platform and module Prediction information
1489 #
1490 # This class reports the platform execution order prediction section and
1491 # module load fixed address prediction subsection in the build report file.
1492 #
1493 class PredictionReport(object):
1494 ##
1495 # Constructor function for class PredictionReport
1496 #
1497 # This constructor function generates PredictionReport object for the platform.
1498 #
1499 # @param self: The object pointer
1500 # @param Wa Workspace context information
1501 #
1502 def __init__(self, Wa):
1503 self._MapFileName = os.path.join(Wa.BuildDir, Wa.Name + ".map")
1504 self._MapFileParsed = False
1505 self._EotToolInvoked = False
1506 self._FvDir = Wa.FvDir
1507 self._EotDir = Wa.BuildDir
1508 self._FfsEntryPoint = {}
1509 self._GuidMap = {}
1510 self._SourceList = []
1511 self.FixedMapDict = {}
1512 self.ItemList = []
1513 self.MaxLen = 0
1514
1515 #
1516 # Collect all platform reference source files and GUID C Name
1517 #
1518 for Pa in Wa.AutoGenObjectList:
1519 for Module in Pa.LibraryAutoGenList + Pa.ModuleAutoGenList:
1520 #
1521 # BASE typed modules are EFI agnostic, so we need not scan
1522 # their source code to find PPI/Protocol produce or consume
1523 # information.
1524 #
1525 if Module.ModuleType == SUP_MODULE_BASE:
1526 continue
1527 #
1528 # Add module referenced source files
1529 #
1530 self._SourceList.append(str(Module))
1531 IncludeList = {}
1532 for Source in Module.SourceFileList:
1533 if os.path.splitext(str(Source))[1].lower() == ".c":
1534 self._SourceList.append(" " + str(Source))
1535 FindIncludeFiles(Source.Path, Module.IncludePathList, IncludeList)
1536 for IncludeFile in IncludeList.values():
1537 self._SourceList.append(" " + IncludeFile)
1538
1539 for Guid in Module.PpiList:
1540 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.PpiList[Guid])
1541 for Guid in Module.ProtocolList:
1542 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.ProtocolList[Guid])
1543 for Guid in Module.GuidList:
1544 self._GuidMap[Guid] = GuidStructureStringToGuidString(Module.GuidList[Guid])
1545
1546 if Module.Guid and not Module.IsLibrary:
1547 EntryPoint = " ".join(Module.Module.ModuleEntryPointList)
1548 if int(str(Module.AutoGenVersion), 0) >= 0x00010005:
1549 RealEntryPoint = "_ModuleEntryPoint"
1550 else:
1551 RealEntryPoint = EntryPoint
1552 if EntryPoint == "_ModuleEntryPoint":
1553 CCFlags = Module.BuildOption.get("CC", {}).get("FLAGS", "")
1554 Match = gGlueLibEntryPoint.search(CCFlags)
1555 if Match:
1556 EntryPoint = Match.group(1)
1557
1558 self._FfsEntryPoint[Module.Guid.upper()] = (EntryPoint, RealEntryPoint)
1559
1560
1561 #
1562 # Collect platform firmware volume list as the input of EOT.
1563 #
1564 self._FvList = []
1565 if Wa.FdfProfile:
1566 for Fd in Wa.FdfProfile.FdDict:
1567 for FdRegion in Wa.FdfProfile.FdDict[Fd].RegionList:
1568 if FdRegion.RegionType != BINARY_FILE_TYPE_FV:
1569 continue
1570 for FvName in FdRegion.RegionDataList:
1571 if FvName in self._FvList:
1572 continue
1573 self._FvList.append(FvName)
1574 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
1575 for Section in Ffs.SectionList:
1576 try:
1577 for FvSection in Section.SectionList:
1578 if FvSection.FvName in self._FvList:
1579 continue
1580 self._FvList.append(FvSection.FvName)
1581 except AttributeError:
1582 pass
1583
1584
1585 ##
1586 # Parse platform fixed address map files
1587 #
1588 # This function parses the platform final fixed address map file to get
1589 # the database of predicted fixed address for module image base, entry point
1590 # etc.
1591 #
1592 # @param self: The object pointer
1593 #
1594 def _ParseMapFile(self):
1595 if self._MapFileParsed:
1596 return
1597 self._MapFileParsed = True
1598 if os.path.isfile(self._MapFileName):
1599 try:
1600 FileContents = open(self._MapFileName).read()
1601 for Match in gMapFileItemPattern.finditer(FileContents):
1602 AddressType = Match.group(1)
1603 BaseAddress = Match.group(2)
1604 EntryPoint = Match.group(3)
1605 Guid = Match.group(4).upper()
1606 List = self.FixedMapDict.setdefault(Guid, [])
1607 List.append((AddressType, BaseAddress, "*I"))
1608 List.append((AddressType, EntryPoint, "*E"))
1609 except:
1610 EdkLogger.warn(None, "Cannot open file to read", self._MapFileName)
1611
1612 ##
1613 # Invokes EOT tool to get the predicted the execution order.
1614 #
1615 # This function invokes EOT tool to calculate the predicted dispatch order
1616 #
1617 # @param self: The object pointer
1618 #
1619 def _InvokeEotTool(self):
1620 if self._EotToolInvoked:
1621 return
1622
1623 self._EotToolInvoked = True
1624 FvFileList = []
1625 for FvName in self._FvList:
1626 FvFile = os.path.join(self._FvDir, FvName + ".Fv")
1627 if os.path.isfile(FvFile):
1628 FvFileList.append(FvFile)
1629
1630 if len(FvFileList) == 0:
1631 return
1632 #
1633 # Write source file list and GUID file list to an intermediate file
1634 # as the input for EOT tool and dispatch List as the output file
1635 # from EOT tool.
1636 #
1637 SourceList = os.path.join(self._EotDir, "SourceFile.txt")
1638 GuidList = os.path.join(self._EotDir, "GuidList.txt")
1639 DispatchList = os.path.join(self._EotDir, "Dispatch.txt")
1640
1641 TempFile = open(SourceList, "w+")
1642 for Item in self._SourceList:
1643 FileWrite(TempFile, Item)
1644 TempFile.close()
1645 TempFile = open(GuidList, "w+")
1646 for Key in self._GuidMap:
1647 FileWrite(TempFile, "%s %s" % (Key, self._GuidMap[Key]))
1648 TempFile.close()
1649
1650 try:
1651 from Eot.EotMain import Eot
1652
1653 #
1654 # Invoke EOT tool and echo its runtime performance
1655 #
1656 EotStartTime = time.time()
1657 Eot(CommandLineOption=False, SourceFileList=SourceList, GuidList=GuidList,
1658 FvFileList=' '.join(FvFileList), Dispatch=DispatchList, IsInit=True)
1659 EotEndTime = time.time()
1660 EotDuration = time.strftime("%H:%M:%S", time.gmtime(int(round(EotEndTime - EotStartTime))))
1661 EdkLogger.quiet("EOT run time: %s\n" % EotDuration)
1662
1663 #
1664 # Parse the output of EOT tool
1665 #
1666 for Line in open(DispatchList):
1667 if len(Line.split()) < 4:
1668 continue
1669 (Guid, Phase, FfsName, FilePath) = Line.split()
1670 Symbol = self._FfsEntryPoint.get(Guid, [FfsName, ""])[0]
1671 if len(Symbol) > self.MaxLen:
1672 self.MaxLen = len(Symbol)
1673 self.ItemList.append((Phase, Symbol, FilePath))
1674 except:
1675 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))
1676 EdkLogger.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1677
1678
1679 ##
1680 # Generate platform execution order report
1681 #
1682 # This function generates the predicted module execution order.
1683 #
1684 # @param self The object pointer
1685 # @param File The file object for report
1686 #
1687 def _GenerateExecutionOrderReport(self, File):
1688 self._InvokeEotTool()
1689 if len(self.ItemList) == 0:
1690 return
1691 FileWrite(File, gSectionStart)
1692 FileWrite(File, "Execution Order Prediction")
1693 FileWrite(File, "*P PEI phase")
1694 FileWrite(File, "*D DXE phase")
1695 FileWrite(File, "*E Module INF entry point name")
1696 FileWrite(File, "*N Module notification function name")
1697
1698 FileWrite(File, "Type %-*s %s" % (self.MaxLen, "Symbol", "Module INF Path"))
1699 FileWrite(File, gSectionSep)
1700 for Item in self.ItemList:
1701 FileWrite(File, "*%sE %-*s %s" % (Item[0], self.MaxLen, Item[1], Item[2]))
1702
1703 FileWrite(File, gSectionStart)
1704
1705 ##
1706 # Generate Fixed Address report.
1707 #
1708 # This function generate the predicted fixed address report for a module
1709 # specified by Guid.
1710 #
1711 # @param self The object pointer
1712 # @param File The file object for report
1713 # @param Guid The module Guid value.
1714 # @param NotifyList The list of all notify function in a module
1715 #
1716 def _GenerateFixedAddressReport(self, File, Guid, NotifyList):
1717 self._ParseMapFile()
1718 FixedAddressList = self.FixedMapDict.get(Guid)
1719 if not FixedAddressList:
1720 return
1721
1722 FileWrite(File, gSubSectionStart)
1723 FileWrite(File, "Fixed Address Prediction")
1724 FileWrite(File, "*I Image Loading Address")
1725 FileWrite(File, "*E Entry Point Address")
1726 FileWrite(File, "*N Notification Function Address")
1727 FileWrite(File, "*F Flash Address")
1728 FileWrite(File, "*M Memory Address")
1729 FileWrite(File, "*S SMM RAM Offset")
1730 FileWrite(File, "TOM Top of Memory")
1731
1732 FileWrite(File, "Type Address Name")
1733 FileWrite(File, gSubSectionSep)
1734 for Item in FixedAddressList:
1735 Type = Item[0]
1736 Value = Item[1]
1737 Symbol = Item[2]
1738 if Symbol == "*I":
1739 Name = "(Image Base)"
1740 elif Symbol == "*E":
1741 Name = self._FfsEntryPoint.get(Guid, ["", "_ModuleEntryPoint"])[1]
1742 elif Symbol in NotifyList:
1743 Name = Symbol
1744 Symbol = "*N"
1745 else:
1746 continue
1747
1748 if "Flash" in Type:
1749 Symbol += "F"
1750 elif "Memory" in Type:
1751 Symbol += "M"
1752 else:
1753 Symbol += "S"
1754
1755 if Value[0] == "-":
1756 Value = "TOM" + Value
1757
1758 FileWrite(File, "%s %-16s %s" % (Symbol, Value, Name))
1759
1760 ##
1761 # Generate report for the prediction part
1762 #
1763 # This function generate the predicted fixed address report for a module or
1764 # predicted module execution order for a platform.
1765 # If the input Guid is None, then, it generates the predicted module execution order;
1766 # otherwise it generated the module fixed loading address for the module specified by
1767 # Guid.
1768 #
1769 # @param self The object pointer
1770 # @param File The file object for report
1771 # @param Guid The module Guid value.
1772 #
1773 def GenerateReport(self, File, Guid):
1774 if Guid:
1775 self._GenerateFixedAddressReport(File, Guid.upper(), [])
1776 else:
1777 self._GenerateExecutionOrderReport(File)
1778
1779 ##
1780 # Reports FD region information
1781 #
1782 # This class reports the FD subsection in the build report file.
1783 # It collects region information of platform flash device.
1784 # If the region is a firmware volume, it lists the set of modules
1785 # and its space information; otherwise, it only lists its region name,
1786 # base address and size in its sub-section header.
1787 # If there are nesting FVs, the nested FVs will list immediate after
1788 # this FD region subsection
1789 #
1790 class FdRegionReport(object):
1791 ##
1792 # Discover all the nested FV name list.
1793 #
1794 # This is an internal worker function to discover the all the nested FV information
1795 # in the parent firmware volume. It uses deep first search algorithm recursively to
1796 # find all the FV list name and append them to the list.
1797 #
1798 # @param self The object pointer
1799 # @param FvName The name of current firmware file system
1800 # @param Wa Workspace context information
1801 #
1802 def _DiscoverNestedFvList(self, FvName, Wa):
1803 FvDictKey=FvName.upper()
1804 if FvDictKey in Wa.FdfProfile.FvDict:
1805 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
1806 for Section in Ffs.SectionList:
1807 try:
1808 for FvSection in Section.SectionList:
1809 if FvSection.FvName in self.FvList:
1810 continue
1811 self._GuidsDb[Ffs.NameGuid.upper()] = FvSection.FvName
1812 self.FvList.append(FvSection.FvName)
1813 self.FvInfo[FvSection.FvName] = ("Nested FV", 0, 0)
1814 self._DiscoverNestedFvList(FvSection.FvName, Wa)
1815 except AttributeError:
1816 pass
1817
1818 ##
1819 # Constructor function for class FdRegionReport
1820 #
1821 # This constructor function generates FdRegionReport object for a specified FdRegion.
1822 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1823 # volume list. This function also collects GUID map in order to dump module identification
1824 # in the final report.
1825 #
1826 # @param self: The object pointer
1827 # @param FdRegion The current FdRegion object
1828 # @param Wa Workspace context information
1829 #
1830 def __init__(self, FdRegion, Wa):
1831 self.Type = FdRegion.RegionType
1832 self.BaseAddress = FdRegion.Offset
1833 self.Size = FdRegion.Size
1834 self.FvList = []
1835 self.FvInfo = {}
1836 self._GuidsDb = {}
1837 self._FvDir = Wa.FvDir
1838 self._WorkspaceDir = Wa.WorkspaceDir
1839
1840 #
1841 # If the input FdRegion is not a firmware volume,
1842 # we are done.
1843 #
1844 if self.Type != BINARY_FILE_TYPE_FV:
1845 return
1846
1847 #
1848 # Find all nested FVs in the FdRegion
1849 #
1850 for FvName in FdRegion.RegionDataList:
1851 if FvName in self.FvList:
1852 continue
1853 self.FvList.append(FvName)
1854 self.FvInfo[FvName] = ("Fd Region", self.BaseAddress, self.Size)
1855 self._DiscoverNestedFvList(FvName, Wa)
1856
1857 PlatformPcds = {}
1858 #
1859 # Collect PCDs declared in DEC files.
1860 #
1861 for Pa in Wa.AutoGenObjectList:
1862 for Package in Pa.PackageList:
1863 for (TokenCName, TokenSpaceGuidCName, DecType) in Package.Pcds:
1864 DecDefaultValue = Package.Pcds[TokenCName, TokenSpaceGuidCName, DecType].DefaultValue
1865 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DecDefaultValue
1866 #
1867 # Collect PCDs defined in DSC file
1868 #
1869 for Pa in Wa.AutoGenObjectList:
1870 for (TokenCName, TokenSpaceGuidCName) in Pa.Platform.Pcds:
1871 DscDefaultValue = Pa.Platform.Pcds[(TokenCName, TokenSpaceGuidCName)].DefaultValue
1872 PlatformPcds[(TokenCName, TokenSpaceGuidCName)] = DscDefaultValue
1873
1874 #
1875 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1876 #
1877 self._GuidsDb[PEI_APRIORI_GUID] = "PEI Apriori"
1878 self._GuidsDb[DXE_APRIORI_GUID] = "DXE Apriori"
1879 #
1880 # Add ACPI table storage file
1881 #
1882 self._GuidsDb["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1883
1884 for Pa in Wa.AutoGenObjectList:
1885 for ModuleKey in Pa.Platform.Modules:
1886 M = Pa.Platform.Modules[ModuleKey].M
1887 InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File)
1888 self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath)
1889
1890 #
1891 # Collect the GUID map in the FV firmware volume
1892 #
1893 for FvName in self.FvList:
1894 FvDictKey=FvName.upper()
1895 if FvDictKey in Wa.FdfProfile.FvDict:
1896 for Ffs in Wa.FdfProfile.FvDict[FvName.upper()].FfsList:
1897 try:
1898 #
1899 # collect GUID map for binary EFI file in FDF file.
1900 #
1901 Guid = Ffs.NameGuid.upper()
1902 Match = gPcdGuidPattern.match(Ffs.NameGuid)
1903 if Match:
1904 PcdTokenspace = Match.group(1)
1905 PcdToken = Match.group(2)
1906 if (PcdToken, PcdTokenspace) in PlatformPcds:
1907 GuidValue = PlatformPcds[(PcdToken, PcdTokenspace)]
1908 Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()
1909 for Section in Ffs.SectionList:
1910 try:
1911 ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName)
1912 self._GuidsDb[Guid] = ModuleSectFile
1913 except AttributeError:
1914 pass
1915 except AttributeError:
1916 pass
1917
1918
1919 ##
1920 # Internal worker function to generate report for the FD region
1921 #
1922 # This internal worker function to generate report for the FD region.
1923 # It the type is firmware volume, it lists offset and module identification.
1924 #
1925 # @param self The object pointer
1926 # @param File The file object for report
1927 # @param Title The title for the FD subsection
1928 # @param BaseAddress The base address for the FD region
1929 # @param Size The size of the FD region
1930 # @param FvName The FV name if the FD region is a firmware volume
1931 #
1932 def _GenerateReport(self, File, Title, Type, BaseAddress, Size=0, FvName=None):
1933 FileWrite(File, gSubSectionStart)
1934 FileWrite(File, Title)
1935 FileWrite(File, "Type: %s" % Type)
1936 FileWrite(File, "Base Address: 0x%X" % BaseAddress)
1937
1938 if self.Type == BINARY_FILE_TYPE_FV:
1939 FvTotalSize = 0
1940 FvTakenSize = 0
1941 FvFreeSize = 0
1942 if FvName.upper().endswith('.FV'):
1943 FileExt = FvName + ".txt"
1944 else:
1945 FileExt = FvName + ".Fv.txt"
1946
1947 if not os.path.isfile(FileExt):
1948 FvReportFileName = mws.join(self._WorkspaceDir, FileExt)
1949 if not os.path.isfile(FvReportFileName):
1950 FvReportFileName = os.path.join(self._FvDir, FileExt)
1951 try:
1952 #
1953 # Collect size info in the firmware volume.
1954 #
1955 FvReport = open(FvReportFileName).read()
1956 Match = gFvTotalSizePattern.search(FvReport)
1957 if Match:
1958 FvTotalSize = int(Match.group(1), 16)
1959 Match = gFvTakenSizePattern.search(FvReport)
1960 if Match:
1961 FvTakenSize = int(Match.group(1), 16)
1962 FvFreeSize = FvTotalSize - FvTakenSize
1963 #
1964 # Write size information to the report file.
1965 #
1966 FileWrite(File, "Size: 0x%X (%.0fK)" % (FvTotalSize, FvTotalSize / 1024.0))
1967 FileWrite(File, "Fv Name: %s (%.1f%% Full)" % (FvName, FvTakenSize * 100.0 / FvTotalSize))
1968 FileWrite(File, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize, FvTakenSize / 1024.0))
1969 FileWrite(File, "Free Size: 0x%X (%.0fK)" % (FvFreeSize, FvFreeSize / 1024.0))
1970 FileWrite(File, "Offset Module")
1971 FileWrite(File, gSubSectionSep)
1972 #
1973 # Write module offset and module identification to the report file.
1974 #
1975 OffsetInfo = {}
1976 for Match in gOffsetGuidPattern.finditer(FvReport):
1977 Guid = Match.group(2).upper()
1978 OffsetInfo[Match.group(1)] = self._GuidsDb.get(Guid, Guid)
1979 OffsetList = sorted(OffsetInfo.keys())
1980 for Offset in OffsetList:
1981 FileWrite (File, "%s %s" % (Offset, OffsetInfo[Offset]))
1982 except IOError:
1983 EdkLogger.warn(None, "Fail to read report file", FvReportFileName)
1984 else:
1985 FileWrite(File, "Size: 0x%X (%.0fK)" % (Size, Size / 1024.0))
1986 FileWrite(File, gSubSectionEnd)
1987
1988 ##
1989 # Generate report for the FD region
1990 #
1991 # This function generates report for the FD region.
1992 #
1993 # @param self The object pointer
1994 # @param File The file object for report
1995 #
1996 def GenerateReport(self, File):
1997 if (len(self.FvList) > 0):
1998 for FvItem in self.FvList:
1999 Info = self.FvInfo[FvItem]
2000 self._GenerateReport(File, Info[0], TAB_FV_DIRECTORY, Info[1], Info[2], FvItem)
2001 else:
2002 self._GenerateReport(File, "FD Region", self.Type, self.BaseAddress, self.Size)
2003
2004 ##
2005 # Reports FD information
2006 #
2007 # This class reports the FD section in the build report file.
2008 # It collects flash device information for a platform.
2009 #
2010 class FdReport(object):
2011 ##
2012 # Constructor function for class FdReport
2013 #
2014 # This constructor function generates FdReport object for a specified
2015 # firmware device.
2016 #
2017 # @param self The object pointer
2018 # @param Fd The current Firmware device object
2019 # @param Wa Workspace context information
2020 #
2021 def __init__(self, Fd, Wa):
2022 self.FdName = Fd.FdUiName
2023 self.BaseAddress = Fd.BaseAddress
2024 self.Size = Fd.Size
2025 self.FdRegionList = [FdRegionReport(FdRegion, Wa) for FdRegion in Fd.RegionList]
2026 self.FvPath = os.path.join(Wa.BuildDir, TAB_FV_DIRECTORY)
2027 self.VPDBaseAddress = 0
2028 self.VPDSize = 0
2029 for index, FdRegion in enumerate(Fd.RegionList):
2030 if str(FdRegion.RegionType) is 'FILE' and Wa.Platform.VpdToolGuid in str(FdRegion.RegionDataList):
2031 self.VPDBaseAddress = self.FdRegionList[index].BaseAddress
2032 self.VPDSize = self.FdRegionList[index].Size
2033 break
2034
2035 ##
2036 # Generate report for the firmware device.
2037 #
2038 # This function generates report for the firmware device.
2039 #
2040 # @param self The object pointer
2041 # @param File The file object for report
2042 #
2043 def GenerateReport(self, File):
2044 FileWrite(File, gSectionStart)
2045 FileWrite(File, "Firmware Device (FD)")
2046 FileWrite(File, "FD Name: %s" % self.FdName)
2047 FileWrite(File, "Base Address: %s" % self.BaseAddress)
2048 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.Size, self.Size / 1024.0))
2049 if len(self.FdRegionList) > 0:
2050 FileWrite(File, gSectionSep)
2051 for FdRegionItem in self.FdRegionList:
2052 FdRegionItem.GenerateReport(File)
2053
2054 if VPDPcdList:
2055 VPDPcdList.sort(key=lambda x: int(x[2], 0))
2056 FileWrite(File, gSubSectionStart)
2057 FileWrite(File, "FD VPD Region")
2058 FileWrite(File, "Base Address: 0x%X" % self.VPDBaseAddress)
2059 FileWrite(File, "Size: 0x%X (%.0fK)" % (self.VPDSize, self.VPDSize / 1024.0))
2060 FileWrite(File, gSubSectionSep)
2061 for item in VPDPcdList:
2062 # Add BaseAddress for offset
2063 Offset = '0x%08X' % (int(item[2], 16) + self.VPDBaseAddress)
2064 IsByteArray, ArrayList = ByteArrayForamt(item[-1])
2065 Skuinfo = item[1]
2066 if len(GlobalData.gSkuids) == 1 :
2067 Skuinfo = GlobalData.gSkuids[0]
2068 if IsByteArray:
2069 FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], '{'))
2070 for Array in ArrayList:
2071 FileWrite(File, Array)
2072 else:
2073 FileWrite(File, "%s | %s | %s | %s | %s" % (item[0], Skuinfo, Offset, item[3], item[-1]))
2074 FileWrite(File, gSubSectionEnd)
2075 FileWrite(File, gSectionEnd)
2076
2077
2078
2079 ##
2080 # Reports platform information
2081 #
2082 # This class reports the whole platform information
2083 #
2084 class PlatformReport(object):
2085 ##
2086 # Constructor function for class PlatformReport
2087 #
2088 # This constructor function generates PlatformReport object a platform build.
2089 # It generates report for platform summary, flash, global PCDs and detailed
2090 # module information for modules involved in platform build.
2091 #
2092 # @param self The object pointer
2093 # @param Wa Workspace context information
2094 # @param MaList The list of modules in the platform build
2095 #
2096 def __init__(self, Wa, MaList, ReportType):
2097 self._WorkspaceDir = Wa.WorkspaceDir
2098 self.PlatformName = Wa.Name
2099 self.PlatformDscPath = Wa.Platform
2100 self.Architectures = " ".join(Wa.ArchList)
2101 self.ToolChain = Wa.ToolChain
2102 self.Target = Wa.BuildTarget
2103 self.OutputPath = os.path.join(Wa.WorkspaceDir, Wa.OutputDir)
2104 self.BuildEnvironment = platform.platform()
2105
2106 self.PcdReport = None
2107 if "PCD" in ReportType:
2108 self.PcdReport = PcdReport(Wa)
2109
2110 self.FdReportList = []
2111 if "FLASH" in ReportType and Wa.FdfProfile and MaList is None:
2112 for Fd in Wa.FdfProfile.FdDict:
2113 self.FdReportList.append(FdReport(Wa.FdfProfile.FdDict[Fd], Wa))
2114
2115 self.PredictionReport = None
2116 if "FIXED_ADDRESS" in ReportType or "EXECUTION_ORDER" in ReportType:
2117 self.PredictionReport = PredictionReport(Wa)
2118
2119 self.DepexParser = None
2120 if "DEPEX" in ReportType:
2121 self.DepexParser = DepexParser(Wa)
2122
2123 self.ModuleReportList = []
2124 if MaList is not None:
2125 self._IsModuleBuild = True
2126 for Ma in MaList:
2127 self.ModuleReportList.append(ModuleReport(Ma, ReportType))
2128 else:
2129 self._IsModuleBuild = False
2130 for Pa in Wa.AutoGenObjectList:
2131 ModuleAutoGenList = []
2132 for ModuleKey in Pa.Platform.Modules:
2133 ModuleAutoGenList.append(Pa.Platform.Modules[ModuleKey].M)
2134 if GlobalData.gFdfParser is not None:
2135 if Pa.Arch in GlobalData.gFdfParser.Profile.InfDict:
2136 INFList = GlobalData.gFdfParser.Profile.InfDict[Pa.Arch]
2137 for InfName in INFList:
2138 InfClass = PathClass(NormPath(InfName), Wa.WorkspaceDir, Pa.Arch)
2139 Ma = ModuleAutoGen(Wa, InfClass, Pa.BuildTarget, Pa.ToolChain, Pa.Arch, Wa.MetaFile)
2140 if Ma is None:
2141 continue
2142 if Ma not in ModuleAutoGenList:
2143 ModuleAutoGenList.append(Ma)
2144 for MGen in ModuleAutoGenList:
2145 self.ModuleReportList.append(ModuleReport(MGen, ReportType))
2146
2147
2148
2149 ##
2150 # Generate report for the whole platform.
2151 #
2152 # This function generates report for platform information.
2153 # It comprises of platform summary, global PCD, flash and
2154 # module list sections.
2155 #
2156 # @param self The object pointer
2157 # @param File The file object for report
2158 # @param BuildDuration The total time to build the modules
2159 # @param AutoGenTime The total time of AutoGen Phase
2160 # @param MakeTime The total time of Make Phase
2161 # @param GenFdsTime The total time of GenFds Phase
2162 # @param ReportType The kind of report items in the final report file
2163 #
2164 def GenerateReport(self, File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, ReportType):
2165 FileWrite(File, "Platform Summary")
2166 FileWrite(File, "Platform Name: %s" % self.PlatformName)
2167 FileWrite(File, "Platform DSC Path: %s" % self.PlatformDscPath)
2168 FileWrite(File, "Architectures: %s" % self.Architectures)
2169 FileWrite(File, "Tool Chain: %s" % self.ToolChain)
2170 FileWrite(File, "Target: %s" % self.Target)
2171 if GlobalData.gSkuids:
2172 FileWrite(File, "SKUID: %s" % " ".join(GlobalData.gSkuids))
2173 if GlobalData.gDefaultStores:
2174 FileWrite(File, "DefaultStore: %s" % " ".join(GlobalData.gDefaultStores))
2175 FileWrite(File, "Output Path: %s" % self.OutputPath)
2176 FileWrite(File, "Build Environment: %s" % self.BuildEnvironment)
2177 FileWrite(File, "Build Duration: %s" % BuildDuration)
2178 if AutoGenTime:
2179 FileWrite(File, "AutoGen Duration: %s" % AutoGenTime)
2180 if MakeTime:
2181 FileWrite(File, "Make Duration: %s" % MakeTime)
2182 if GenFdsTime:
2183 FileWrite(File, "GenFds Duration: %s" % GenFdsTime)
2184 FileWrite(File, "Report Content: %s" % ", ".join(ReportType))
2185
2186 if GlobalData.MixedPcd:
2187 FileWrite(File, gSectionStart)
2188 FileWrite(File, "The following PCDs use different access methods:")
2189 FileWrite(File, gSectionSep)
2190 for PcdItem in GlobalData.MixedPcd:
2191 FileWrite(File, "%s.%s" % (str(PcdItem[1]), str(PcdItem[0])))
2192 FileWrite(File, gSectionEnd)
2193
2194 if not self._IsModuleBuild:
2195 if "PCD" in ReportType:
2196 self.PcdReport.GenerateReport(File, None)
2197
2198 if "FLASH" in ReportType:
2199 for FdReportListItem in self.FdReportList:
2200 FdReportListItem.GenerateReport(File)
2201
2202 for ModuleReportItem in self.ModuleReportList:
2203 ModuleReportItem.GenerateReport(File, self.PcdReport, self.PredictionReport, self.DepexParser, ReportType)
2204
2205 if not self._IsModuleBuild:
2206 if "EXECUTION_ORDER" in ReportType:
2207 self.PredictionReport.GenerateReport(File, None)
2208
2209 ## BuildReport class
2210 #
2211 # This base class contain the routines to collect data and then
2212 # applies certain format to the output report
2213 #
2214 class BuildReport(object):
2215 ##
2216 # Constructor function for class BuildReport
2217 #
2218 # This constructor function generates BuildReport object a platform build.
2219 # It generates report for platform summary, flash, global PCDs and detailed
2220 # module information for modules involved in platform build.
2221 #
2222 # @param self The object pointer
2223 # @param ReportFile The file name to save report file
2224 # @param ReportType The kind of report items in the final report file
2225 #
2226 def __init__(self, ReportFile, ReportType):
2227 self.ReportFile = ReportFile
2228 if ReportFile:
2229 self.ReportList = []
2230 self.ReportType = []
2231 if ReportType:
2232 for ReportTypeItem in ReportType:
2233 if ReportTypeItem not in self.ReportType:
2234 self.ReportType.append(ReportTypeItem)
2235 else:
2236 self.ReportType = ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "HASH", "FLASH", "FIXED_ADDRESS"]
2237 ##
2238 # Adds platform report to the list
2239 #
2240 # This function adds a platform report to the final report list.
2241 #
2242 # @param self The object pointer
2243 # @param Wa Workspace context information
2244 # @param MaList The list of modules in the platform build
2245 #
2246 def AddPlatformReport(self, Wa, MaList=None):
2247 if self.ReportFile:
2248 self.ReportList.append((Wa, MaList))
2249
2250 ##
2251 # Generates the final report.
2252 #
2253 # This function generates platform build report. It invokes GenerateReport()
2254 # method for every platform report in the list.
2255 #
2256 # @param self The object pointer
2257 # @param BuildDuration The total time to build the modules
2258 # @param AutoGenTime The total time of AutoGen phase
2259 # @param MakeTime The total time of Make phase
2260 # @param GenFdsTime The total time of GenFds phase
2261 #
2262 def GenerateReport(self, BuildDuration, AutoGenTime, MakeTime, GenFdsTime):
2263 if self.ReportFile:
2264 try:
2265 File = BytesIO('')
2266 for (Wa, MaList) in self.ReportList:
2267 PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, self.ReportType)
2268 Content = FileLinesSplit(File.getvalue(), gLineMaxLength)
2269 SaveFileOnChange(self.ReportFile, Content, True)
2270 EdkLogger.quiet("Build report can be found at %s" % os.path.abspath(self.ReportFile))
2271 except IOError:
2272 EdkLogger.error(None, FILE_WRITE_FAILURE, ExtraData=self.ReportFile)
2273 except:
2274 EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report", ExtraData=self.ReportFile, RaiseError=False)
2275 EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))
2276 File.close()
2277
2278 # This acts like the main() function for the script, unless it is 'import'ed into another script.
2279 if __name__ == '__main__':
2280 pass
2281