2 # Routines for generating build report.
4 # This module contains the functionality to generate build report after
5 # build all target completes successfully.
7 # Copyright (c) 2010, 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
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.
27 from datetime
import datetime
28 from StringIO
import StringIO
29 from Common
import EdkLogger
30 from Common
.Misc
import SaveFileOnChange
31 from Common
.Misc
import GuidStructureByteArrayToGuidString
32 from Common
.Misc
import GuidStructureStringToGuidString
33 from Common
.InfClassObject
import gComponentType2ModuleType
34 from Common
.BuildToolError
import FILE_WRITE_FAILURE
35 from Common
.BuildToolError
import CODE_ERROR
38 ## Pattern to extract contents in EDK DXS files
39 gDxsDependencyPattern
= re
.compile(r
"DEPENDENCY_START(.+)DEPENDENCY_END", re
.DOTALL
)
41 ## Pattern to find total FV total size, occupied size in flash report intermediate file
42 gFvTotalSizePattern
= re
.compile(r
"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
43 gFvTakenSizePattern
= re
.compile(r
"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
45 ## Pattern to find module size and time stamp in module summary report intermediate file
46 gModuleSizePattern
= re
.compile(r
"MODULE_SIZE = (\d+)")
47 gTimeStampPattern
= re
.compile(r
"TIME_STAMP = (\d+)")
49 ## Pattern to find GUID value in flash description files
50 gPcdGuidPattern
= re
.compile(r
"PCD\((\w+)[.](\w+)\)")
52 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
53 gOffsetGuidPattern
= re
.compile(r
"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
55 ## Pattern to find module base address and entry point in fixed flash map file
56 gModulePattern
= r
"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
57 gMapFileItemPattern
= re
.compile(gModulePattern
% {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
59 ## Pattern to find all module referenced header files in source files
60 gIncludePattern
= re
.compile(r
'#include\s*["<]([^">]+)[">]')
61 gIncludePattern2
= re
.compile(r
"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
63 ## Pattern to find the entry point for EDK module using EDKII Glue library
64 gGlueLibEntryPoint
= re
.compile(r
"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
66 ## Tags for section start, end and separator
67 gSectionStart
= ">" + "=" * 118 + "<"
68 gSectionEnd
= "<" + "=" * 118 + ">" + "\n"
69 gSectionSep
= "=" * 120
71 ## Tags for subsection start, end and separator
72 gSubSectionStart
= ">" + "-" * 118 + "<"
73 gSubSectionEnd
= "<" + "-" * 118 + ">"
74 gSubSectionSep
= "-" * 120
76 ## The look up table to map PCD type to pair of report display type and DEC type
78 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),
79 'PatchableInModule': ('PATCH', 'PatchableInModule'),
80 'FeatureFlag' : ('FLAG', 'FeatureFlag'),
81 'Dynamic' : ('DYN', 'Dynamic'),
82 'DynamicHii' : ('DYNHII', 'Dynamic'),
83 'DynamicVpd' : ('DYNVPD', 'Dynamic'),
84 'DynamicEx' : ('DEX', 'Dynamic'),
85 'DynamicExHii' : ('DEXHII', 'Dynamic'),
86 'DynamicExVpd' : ('DEXVPD', 'Dynamic'),
89 ## The look up table to map module type to driver type
91 'SEC' : '0x3 (SECURITY_CORE)',
92 'PEI_CORE' : '0x4 (PEI_CORE)',
93 'PEIM' : '0x6 (PEIM)',
94 'DXE_CORE' : '0x5 (DXE_CORE)',
95 'DXE_DRIVER' : '0x7 (DRIVER)',
96 'DXE_SAL_DRIVER' : '0x7 (DRIVER)',
97 'DXE_SMM_DRIVER' : '0x7 (DRIVER)',
98 'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',
99 'UEFI_DRIVER' : '0x7 (DRIVER)',
100 'UEFI_APPLICATION' : '0x9 (APPLICATION)',
101 'SMM_CORE' : '0xD (SMM_CORE)',
102 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
105 ## The look up table of the supported opcode in the dependency expression binaries
106 gOpCodeList
= ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
109 # Writes a string to the file object.
111 # This function writes a string to the file object and a new line is appended
112 # afterwards. It may optionally wraps the string for better readability.
114 # @File The file object to write
115 # @String The string to be written to the file
116 # @Wrapper Indicates whether to wrap the string
118 def FileWrite(File
, String
, Wrapper
=False):
120 String
= textwrap
.fill(String
, 120)
121 File
.write(String
+ "\r\n")
124 # Find all the header file that the module source directly includes.
126 # This function scans source code to find all header files the module may
127 # include. This is not accurate but very effective to find all the header
128 # file the module might include with #include statement.
130 # @Source The source file name
131 # @IncludePathList The list of include path to find the source file.
132 # @IncludeFiles The dictionary of current found include files.
134 def FindIncludeFiles(Source
, IncludePathList
, IncludeFiles
):
135 FileContents
= open(Source
).read()
137 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
139 for Match
in gIncludePattern
.finditer(FileContents
):
140 FileName
= Match
.group(1).strip()
141 for Dir
in [os
.path
.dirname(Source
)] + IncludePathList
:
142 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
143 if os
.path
.exists(FullFileName
):
144 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
148 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
150 for Match
in gIncludePattern2
.finditer(FileContents
):
152 Type
= Match
.group(1)
153 if "ARCH_PROTOCOL" in Type
:
154 FileName
= "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
155 elif "PROTOCOL" in Type
:
156 FileName
= "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
158 FileName
= "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key
}
160 FileName
= "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key
}
163 for Dir
in IncludePathList
:
164 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
165 if os
.path
.exists(FullFileName
):
166 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
170 # Parse binary dependency expression section
172 # This utility class parses the dependency expression section and translate the readable
173 # GUID name and value.
175 class DepexParser(object):
177 # Constructor function for class DepexParser
179 # This constructor function collect GUID values so that the readable
180 # GUID name can be translated.
182 # @param self The object pointer
183 # @param Wa Workspace context information
185 def __init__(self
, Wa
):
187 for Package
in Wa
.BuildDatabase
.WorkspaceDb
.PackageList
:
188 for Protocol
in Package
.Protocols
:
189 GuidValue
= GuidStructureStringToGuidString(Package
.Protocols
[Protocol
])
190 self
._GuidDb
[GuidValue
.upper()] = Protocol
191 for Ppi
in Package
.Ppis
:
192 GuidValue
= GuidStructureStringToGuidString(Package
.Ppis
[Ppi
])
193 self
._GuidDb
[GuidValue
.upper()] = Ppi
194 for Guid
in Package
.Guids
:
195 GuidValue
= GuidStructureStringToGuidString(Package
.Guids
[Guid
])
196 self
._GuidDb
[GuidValue
.upper()] = Guid
199 # Parse the binary dependency expression files.
201 # This function parses the binary dependency expression file and translate it
202 # to the instruction list.
204 # @param self The object pointer
205 # @param DepexFileName The file name of binary dependency expression file.
207 def ParseDepexFile(self
, DepexFileName
):
208 DepexFile
= open(DepexFileName
, "rb")
210 OpCode
= DepexFile
.read(1)
212 Statement
= gOpCodeList
[struct
.unpack("B", OpCode
)[0]]
213 if Statement
in ["BEFORE", "AFTER", "PUSH"]:
214 GuidValue
= "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
215 struct
.unpack("LHHBBBBBBBB", DepexFile
.read(16))
216 GuidString
= self
._GuidDb
.get(GuidValue
, GuidValue
)
217 Statement
= "%s %s" % (Statement
, GuidString
)
218 DepexStatement
.append(Statement
)
219 OpCode
= DepexFile
.read(1)
221 return DepexStatement
224 # Reports library information
226 # This class reports the module library subsection in the build report file.
228 class LibraryReport(object):
230 # Constructor function for class LibraryReport
232 # This constructor function generates LibraryReport object for
235 # @param self The object pointer
236 # @param M Module context information
238 def __init__(self
, M
):
239 self
.LibraryList
= []
240 if int(str(M
.AutoGenVersion
), 0) >= 0x00010005:
241 self
._EdkIIModule
= True
243 self
._EdkIIModule
= False
245 for Lib
in M
.DependentLibraryList
:
246 LibInfPath
= str(Lib
)
247 LibClassList
= Lib
.LibraryClass
[0].LibraryClass
248 LibConstructorList
= Lib
.ConstructorList
249 LibDesstructorList
= Lib
.DestructorList
250 LibDepexList
= Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]
251 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
))
254 # Generate report for module library information
256 # This function generates report for the module library.
257 # If the module is EDKII style one, the additional library class, library
258 # constructor/destructor and dependency expression may also be reported.
260 # @param self The object pointer
261 # @param File The file object for report
263 def GenerateReport(self
, File
):
264 FileWrite(File
, gSubSectionStart
)
265 FileWrite(File
, "Library")
266 if len(self
.LibraryList
) > 0:
267 FileWrite(File
, gSubSectionSep
)
268 for LibraryItem
in self
.LibraryList
:
269 LibInfPath
= LibraryItem
[0]
270 FileWrite(File
, LibInfPath
)
273 # Report library class, library constructor and destructor for
274 # EDKII style module.
276 if self
._EdkIIModule
:
277 LibClass
= LibraryItem
[1]
279 LibConstructor
= " ".join(LibraryItem
[2])
281 EdkIILibInfo
+= " C = " + LibConstructor
282 LibDestructor
= " ".join(LibraryItem
[3])
284 EdkIILibInfo
+= " D = " + LibDestructor
285 LibDepex
= " ".join(LibraryItem
[4])
287 EdkIILibInfo
+= " Depex = " + LibDepex
289 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
291 FileWrite(File
, "{%s}" % LibClass
)
293 FileWrite(File
, gSubSectionEnd
)
296 # Reports dependency expression information
298 # This class reports the module dependency expression subsection in the build report file.
300 class DepexReport(object):
302 # Constructor function for class DepexReport
304 # This constructor function generates DepexReport object for
305 # a module. If the module source contains the DXS file (usually EDK
306 # style module), it uses the dependency in DXS file; otherwise,
307 # it uses the dependency expression from its own INF [Depex] section
308 # and then merges with the ones from its dependent library INF.
310 # @param self The object pointer
311 # @param M Module context information
313 def __init__(self
, M
):
315 self
._DepexFileName
= os
.path
.join(M
.BuildDir
, "OUTPUT", M
.Module
.BaseName
+ ".depex")
316 ModuleType
= M
.ModuleType
318 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
320 if ModuleType
in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "UEFI_APPLICATION"]:
323 for Source
in M
.SourceFileList
:
324 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
325 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
327 self
.Depex
= Match
.group(1).strip()
331 self
.Depex
= M
.DepexExpressionList
.get(M
.ModuleType
, "")
332 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
333 if not self
.ModuleDepex
:
334 self
.ModuleDepex
= "(None)"
337 for Lib
in M
.DependentLibraryList
:
338 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
340 LibDepexList
.append("(" + LibDepex
+ ")")
341 self
.LibraryDepex
= " AND ".join(LibDepexList
)
342 if not self
.LibraryDepex
:
343 self
.LibraryDepex
= "(None)"
347 # Generate report for module dependency expression information
349 # This function generates report for the module dependency expression.
351 # @param self The object pointer
352 # @param File The file object for report
353 # @param GlobalDepexParser The platform global Dependency expression parser object
355 def GenerateReport(self
, File
, GlobalDepexParser
):
359 FileWrite(File
, gSubSectionStart
)
360 if os
.path
.isfile(self
._DepexFileName
):
362 DepexStatements
= GlobalDepexParser
.ParseDepexFile(self
._DepexFileName
)
363 FileWrite(File
, "Final Dependency Expression (DEPEX) Instructions")
364 for DepexStatement
in DepexStatements
:
365 FileWrite(File
, " %s" % DepexStatement
)
366 FileWrite(File
, gSubSectionSep
)
368 EdkLogger
.warn(None, "Dependency expression file is corrupted", self
._DepexFileName
)
370 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
372 if self
.Source
== "INF":
373 FileWrite(File
, "%s" % self
.Depex
, True)
374 FileWrite(File
, gSubSectionSep
)
375 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
376 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
378 FileWrite(File
, "%s" % self
.Depex
)
379 FileWrite(File
, gSubSectionEnd
)
382 # Reports dependency expression information
384 # This class reports the module build flags subsection in the build report file.
386 class BuildFlagsReport(object):
388 # Constructor function for class BuildFlagsReport
390 # This constructor function generates BuildFlagsReport object for
391 # a module. It reports the build tool chain tag and all relevant
392 # build flags to build the module.
394 # @param self The object pointer
395 # @param M Module context information
397 def __init__(self
, M
):
400 # Add build flags according to source file extension so that
401 # irrelevant ones can be filtered out.
403 for Source
in M
.SourceFileList
:
404 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
405 if Ext
in [".c", ".cc", ".cpp"]:
406 BuildOptions
["CC"] = 1
407 elif Ext
in [".s", ".asm"]:
408 BuildOptions
["PP"] = 1
409 BuildOptions
["ASM"] = 1
410 elif Ext
in [".vfr"]:
411 BuildOptions
["VFRPP"] = 1
412 BuildOptions
["VFR"] = 1
413 elif Ext
in [".dxs"]:
414 BuildOptions
["APP"] = 1
415 BuildOptions
["CC"] = 1
416 elif Ext
in [".asl"]:
417 BuildOptions
["ASLPP"] = 1
418 BuildOptions
["ASL"] = 1
419 elif Ext
in [".aslc"]:
420 BuildOptions
["ASLCC"] = 1
421 BuildOptions
["ASLDLINK"] = 1
422 BuildOptions
["CC"] = 1
423 elif Ext
in [".asm16"]:
424 BuildOptions
["ASMLINK"] = 1
425 BuildOptions
["SLINK"] = 1
426 BuildOptions
["DLINK"] = 1
429 # Save module build flags.
431 self
.ToolChainTag
= M
.ToolChain
433 for Tool
in BuildOptions
:
434 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
437 # Generate report for module build flags information
439 # This function generates report for the module build flags expression.
441 # @param self The object pointer
442 # @param File The file object for report
444 def GenerateReport(self
, File
):
445 FileWrite(File
, gSubSectionStart
)
446 FileWrite(File
, "Build Flags")
447 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
448 for Tool
in self
.BuildFlags
:
449 FileWrite(File
, gSubSectionSep
)
450 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
452 FileWrite(File
, gSubSectionEnd
)
456 # Reports individual module information
458 # This class reports the module section in the build report file.
459 # It comprises of module summary, module PCD, library, dependency expression,
460 # build flags sections.
462 class ModuleReport(object):
464 # Constructor function for class ModuleReport
466 # This constructor function generates ModuleReport object for
467 # a separate module in a platform build.
469 # @param self The object pointer
470 # @param M Module context information
471 # @param ReportType The kind of report items in the final report file
473 def __init__(self
, M
, ReportType
):
474 self
.ModuleName
= M
.Module
.BaseName
475 self
.ModuleInfPath
= M
.MetaFile
.File
476 self
.FileGuid
= M
.Guid
478 self
.BuildTimeStamp
= None
481 ModuleType
= M
.ModuleType
483 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
485 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
487 if ModuleType
== "DXE_SMM_DRIVER":
488 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
489 if int(PiSpec
, 0) >= 0x0001000A:
490 ModuleType
= "SMM_DRIVER"
491 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
492 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
493 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
494 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
495 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
496 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
498 self
._BuildDir
= M
.BuildDir
499 self
.ModulePcdSet
= {}
500 if "PCD" in ReportType
:
502 # Collect all module used PCD set: module INF referenced directly or indirectly.
503 # It also saves module INF default values of them in case they exist.
505 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
506 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
508 self
.LibraryReport
= None
509 if "LIBRARY" in ReportType
:
510 self
.LibraryReport
= LibraryReport(M
)
512 self
.DepexReport
= None
513 if "DEPEX" in ReportType
:
514 self
.DepexReport
= DepexReport(M
)
516 if "BUILD_FLAGS" in ReportType
:
517 self
.BuildFlagsReport
= BuildFlagsReport(M
)
521 # Generate report for module information
523 # This function generates report for separate module expression
524 # in a platform build.
526 # @param self The object pointer
527 # @param File The file object for report
528 # @param GlobalPcdReport The platform global PCD report object
529 # @param GlobalPredictionReport The platform global Prediction report object
530 # @param GlobalDepexParser The platform global Dependency expression parser object
531 # @param ReportType The kind of report items in the final report file
533 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, GlobalDepexParser
, ReportType
):
534 FileWrite(File
, gSectionStart
)
536 FwReportFileName
= os
.path
.join(self
._BuildDir
, "DEBUG", self
.ModuleName
+ ".txt")
537 if os
.path
.isfile(FwReportFileName
):
539 FileContents
= open(FwReportFileName
).read()
540 Match
= gModuleSizePattern
.search(FileContents
)
542 self
.Size
= int(Match
.group(1))
544 Match
= gTimeStampPattern
.search(FileContents
)
546 self
.BuildTimeStamp
= datetime
.fromtimestamp(int(Match
.group(1)))
548 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
550 FileWrite(File
, "Module Summary")
551 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
552 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
553 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
555 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
556 if self
.BuildTimeStamp
:
557 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
559 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
560 if self
.UefiSpecVersion
:
561 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
562 if self
.PiSpecVersion
:
563 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
565 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
567 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
568 if self
.PciClassCode
:
569 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
571 FileWrite(File
, gSectionSep
)
573 if "PCD" in ReportType
:
574 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
576 if "LIBRARY" in ReportType
:
577 self
.LibraryReport
.GenerateReport(File
)
579 if "DEPEX" in ReportType
:
580 self
.DepexReport
.GenerateReport(File
, GlobalDepexParser
)
582 if "BUILD_FLAGS" in ReportType
:
583 self
.BuildFlagsReport
.GenerateReport(File
)
585 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
586 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
588 FileWrite(File
, gSectionEnd
)
591 # Reports platform and module PCD information
593 # This class reports the platform PCD section and module PCD subsection
594 # in the build report file.
596 class PcdReport(object):
598 # Constructor function for class PcdReport
600 # This constructor function generates PcdReport object a platform build.
601 # It collects the whole PCD database from platform DSC files, platform
602 # flash description file and package DEC files.
604 # @param self The object pointer
605 # @param Wa Workspace context information
607 def __init__(self
, Wa
):
611 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
615 self
.ModulePcdOverride
= {}
616 for Pa
in Wa
.AutoGenObjectList
:
618 # Collect all platform referenced PCDs and grouped them by PCD token space
621 for Pcd
in Pa
.AllPcdList
:
622 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
623 if Pcd
not in PcdList
:
625 if len(Pcd
.TokenCName
) > self
.MaxLen
:
626 self
.MaxLen
= len(Pcd
.TokenCName
)
628 for Module
in Pa
.Platform
.Modules
.values():
630 # Collect module override PCDs
632 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
633 TokenCName
= ModulePcd
.TokenCName
634 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
635 ModuleDefault
= ModulePcd
.DefaultValue
636 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
637 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
641 # Collect PCD DEC default value.
643 self
.DecPcdDefault
= {}
644 for Package
in Wa
.BuildDatabase
.WorkspaceDb
.PackageList
:
645 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
646 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
647 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
649 # Collect PCDs defined in DSC common section
651 self
.DscPcdDefault
= {}
652 for Platform
in Wa
.BuildDatabase
.WorkspaceDb
.PlatformList
:
653 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
654 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
656 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
659 # Generate report for PCD information
661 # This function generates report for separate module expression
662 # in a platform build.
664 # @param self The object pointer
665 # @param File The file object for report
666 # @param ModulePcdSet Set of all PCDs referenced by module or None for
667 # platform PCD report
668 # @param DscOverridePcds Module DSC override PCDs set
670 def GenerateReport(self
, File
, ModulePcdSet
):
671 if ModulePcdSet
== None:
673 # For platform global PCD section
675 FileWrite(File
, gSectionStart
)
676 FileWrite(File
, "Platform Configuration Database Report")
677 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
678 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
679 FileWrite(File
, " *M - Module scoped PCD override")
680 FileWrite(File
, gSectionSep
)
683 # For module PCD sub-section
685 FileWrite(File
, gSubSectionStart
)
686 FileWrite(File
, "PCD")
687 FileWrite(File
, gSubSectionSep
)
689 for Key
in self
.AllPcds
:
691 # Group PCD by their token space GUID C Name
694 for Type
in self
.AllPcds
[Key
]:
696 # Group PCD by their usage type
698 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
699 for Pcd
in self
.AllPcds
[Key
][Type
]:
701 # Get PCD default value and their override relationship
703 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
704 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
705 DscDefaultValue
= self
.FdfPcdSet
.get((Pcd
.TokenCName
, Key
), DscDefaultValue
)
706 InfDefaultValue
= None
708 PcdValue
= DecDefaultValue
710 PcdValue
= DscDefaultValue
711 if ModulePcdSet
!= None:
712 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
714 InfDefault
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
718 if ModulePcdSet
== None:
724 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
725 PcdValueNumber
= int(PcdValue
.strip(), 0)
726 if DecDefaultValue
== None:
729 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
730 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
732 if InfDefaultValue
== None:
735 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
736 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
738 if DscDefaultValue
== None:
741 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
742 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
744 if DecDefaultValue
== None:
747 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
749 if InfDefaultValue
== None:
752 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
754 if DscDefaultValue
== None:
757 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
760 # Report PCD item according to their override relationship
762 if DecMatch
and InfMatch
:
763 FileWrite(File
, ' %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
766 if (Pcd
.TokenCName
, Key
) in self
.FdfPcdSet
:
767 FileWrite(File
, ' *F %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
769 FileWrite(File
, ' *P %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
771 FileWrite(File
, ' *M %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
773 if TypeName
in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):
774 for SkuInfo
in Pcd
.SkuInfoList
.values():
775 if TypeName
in ('DYNHII', 'DEXHII'):
776 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
778 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
780 if not DscMatch
and DscDefaultValue
!= None:
781 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', DscDefaultValue
.strip()))
783 if not InfMatch
and InfDefaultValue
!= None:
784 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', InfDefaultValue
.strip()))
786 if not DecMatch
and DecDefaultValue
!= None:
787 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', DecDefaultValue
.strip()))
789 if ModulePcdSet
== None:
790 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
791 for ModulePath
in ModuleOverride
:
792 ModuleDefault
= ModuleOverride
[ModulePath
]
793 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
794 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
795 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
797 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
800 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 19, ModulePath
, ModuleDefault
.strip()))
802 if ModulePcdSet
== None:
803 FileWrite(File
, gSectionEnd
)
805 FileWrite(File
, gSubSectionEnd
)
810 # Reports platform and module Prediction information
812 # This class reports the platform execution order prediction section and
813 # module load fixed address prediction subsection in the build report file.
815 class PredictionReport(object):
817 # Constructor function for class PredictionReport
819 # This constructor function generates PredictionReport object for the platform.
821 # @param self: The object pointer
822 # @param Wa Workspace context information
824 def __init__(self
, Wa
):
825 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
826 self
._MapFileParsed
= False
827 self
._EotToolInvoked
= False
828 self
._FvDir
= Wa
.FvDir
829 self
._EotDir
= Wa
.BuildDir
830 self
._FfsEntryPoint
= {}
832 self
._SourceList
= []
833 self
.FixedMapDict
= {}
838 # Collect all platform reference source files and GUID C Name
840 for Pa
in Wa
.AutoGenObjectList
:
841 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
843 # BASE typed modules are EFI agnostic, so we need not scan
844 # their source code to find PPI/Protocol produce or consume
847 if Module
.ModuleType
== "BASE":
850 # Add module referenced source files
852 self
._SourceList
.append(str(Module
))
854 for Source
in Module
.SourceFileList
:
855 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
856 self
._SourceList
.append(" " + str(Source
))
857 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
858 for IncludeFile
in IncludeList
.values():
859 self
._SourceList
.append(" " + IncludeFile
)
861 for Guid
in Module
.PpiList
:
862 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
863 for Guid
in Module
.ProtocolList
:
864 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
865 for Guid
in Module
.GuidList
:
866 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
868 if Module
.Guid
and not Module
.IsLibrary
:
869 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
870 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
871 RealEntryPoint
= "_ModuleEntryPoint"
873 RealEntryPoint
= EntryPoint
874 if EntryPoint
== "_ModuleEntryPoint":
875 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
876 Match
= gGlueLibEntryPoint
.search(CCFlags
)
878 EntryPoint
= Match
.group(1)
880 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
884 # Collect platform firmware volume list as the input of EOT.
888 for Fd
in Wa
.FdfProfile
.FdDict
:
889 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
890 if FdRegion
.RegionType
!= "FV":
892 for FvName
in FdRegion
.RegionDataList
:
893 if FvName
in self
._FvList
:
895 self
._FvList
.append(FvName
)
896 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
897 for Section
in Ffs
.SectionList
:
899 for FvSection
in Section
.SectionList
:
900 if FvSection
.FvName
in self
._FvList
:
902 self
._FvList
.append(FvSection
.FvName
)
903 except AttributeError:
908 # Parse platform fixed address map files
910 # This function parses the platform final fixed address map file to get
911 # the database of predicted fixed address for module image base, entry point
914 # @param self: The object pointer
916 def _ParseMapFile(self
):
917 if self
._MapFileParsed
:
919 self
._MapFileParsed
= True
920 if os
.path
.isfile(self
._MapFileName
):
922 FileContents
= open(self
._MapFileName
).read()
923 for Match
in gMapFileItemPattern
.finditer(FileContents
):
924 AddressType
= Match
.group(1)
925 BaseAddress
= Match
.group(2)
926 EntryPoint
= Match
.group(3)
927 Guid
= Match
.group(4).upper()
928 List
= self
.FixedMapDict
.setdefault(Guid
, [])
929 List
.append((AddressType
, BaseAddress
, "*I"))
930 List
.append((AddressType
, EntryPoint
, "*E"))
932 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
935 # Invokes EOT tool to get the predicted the execution order.
937 # This function invokes EOT tool to calculate the predicted dispatch order
939 # @param self: The object pointer
941 def _InvokeEotTool(self
):
942 if self
._EotToolInvoked
:
945 self
._EotToolInvoked
= True
947 for FvName
in self
._FvList
:
948 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
949 if os
.path
.isfile(FvFile
):
950 FvFileList
.append(FvFile
)
952 if len(FvFileList
) == 0:
955 # Write source file list and GUID file list to an intermediate file
956 # as the input for EOT tool and dispatch List as the output file
959 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
960 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
961 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
963 TempFile
= open(SourceList
, "w+")
964 for Item
in self
._SourceList
:
965 FileWrite(TempFile
, Item
)
967 TempFile
= open(GuidList
, "w+")
968 for Key
in self
._GuidMap
:
969 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
973 from Eot
.Eot
import Eot
976 # Invoke EOT tool and echo its runtime performance
978 EotStartTime
= time
.time()
979 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
980 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
981 EotEndTime
= time
.time()
982 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
983 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
986 # Parse the output of EOT tool
988 for Line
in open(DispatchList
):
989 if len(Line
.split()) < 4:
991 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
992 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
993 if len(Symbol
) > self
.MaxLen
:
994 self
.MaxLen
= len(Symbol
)
995 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
997 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
998 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1002 # Generate platform execution order report
1004 # This function generates the predicted module execution order.
1006 # @param self The object pointer
1007 # @param File The file object for report
1009 def _GenerateExecutionOrderReport(self
, File
):
1010 self
._InvokeEotTool
()
1011 if len(self
.ItemList
) == 0:
1013 FileWrite(File
, gSectionStart
)
1014 FileWrite(File
, "Execution Order Prediction")
1015 FileWrite(File
, "*P PEI phase")
1016 FileWrite(File
, "*D DXE phase")
1017 FileWrite(File
, "*E Module INF entry point name")
1018 FileWrite(File
, "*N Module notification function name")
1020 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1021 FileWrite(File
, gSectionSep
)
1022 for Item
in self
.ItemList
:
1023 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1025 FileWrite(File
, gSectionStart
)
1028 # Generate Fixed Address report.
1030 # This function generate the predicted fixed address report for a module
1031 # specified by Guid.
1033 # @param self The object pointer
1034 # @param File The file object for report
1035 # @param Guid The module Guid value.
1036 # @param NotifyList The list of all notify function in a module
1038 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1039 self
._ParseMapFile
()
1040 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1041 if not FixedAddressList
:
1044 FileWrite(File
, gSubSectionStart
)
1045 FileWrite(File
, "Fixed Address Prediction")
1046 FileWrite(File
, "*I Image Loading Address")
1047 FileWrite(File
, "*E Entry Point Address")
1048 FileWrite(File
, "*N Notification Function Address")
1049 FileWrite(File
, "*F Flash Address")
1050 FileWrite(File
, "*M Memory Address")
1051 FileWrite(File
, "*S SMM RAM Offset")
1052 FileWrite(File
, "TOM Top of Memory")
1054 FileWrite(File
, "Type Address Name")
1055 FileWrite(File
, gSubSectionSep
)
1056 for Item
in FixedAddressList
:
1061 Name
= "(Image Base)"
1062 elif Symbol
== "*E":
1063 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1064 elif Symbol
in NotifyList
:
1072 elif "Memory" in Type
:
1078 Value
= "TOM" + Value
1080 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1083 # Generate report for the prediction part
1085 # This function generate the predicted fixed address report for a module or
1086 # predicted module execution order for a platform.
1087 # If the input Guid is None, then, it generates the predicted module execution order;
1088 # otherwise it generated the module fixed loading address for the module specified by
1091 # @param self The object pointer
1092 # @param File The file object for report
1093 # @param Guid The module Guid value.
1095 def GenerateReport(self
, File
, Guid
):
1097 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1099 self
._GenerateExecutionOrderReport
(File
)
1102 # Reports FD region information
1104 # This class reports the FD subsection in the build report file.
1105 # It collects region information of platform flash device.
1106 # If the region is a firmware volume, it lists the set of modules
1107 # and its space information; otherwise, it only lists its region name,
1108 # base address and size in its sub-section header.
1109 # If there are nesting FVs, the nested FVs will list immediate after
1110 # this FD region subsection
1112 class FdRegionReport(object):
1114 # Discover all the nested FV name list.
1116 # This is an internal worker function to discover the all the nested FV information
1117 # in the parent firmware volume. It uses deep first search algorithm recursively to
1118 # find all the FV list name and append them to the list.
1120 # @param self The object pointer
1121 # @param FvName The name of current firmware file system
1122 # @param Wa Workspace context information
1124 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1125 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1126 for Section
in Ffs
.SectionList
:
1128 for FvSection
in Section
.SectionList
:
1129 if FvSection
.FvName
in self
.FvList
:
1131 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1132 self
.FvList
.append(FvSection
.FvName
)
1133 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1134 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1135 except AttributeError:
1139 # Constructor function for class FdRegionReport
1141 # This constructor function generates FdRegionReport object for a specified FdRegion.
1142 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1143 # volume list. This function also collects GUID map in order to dump module identification
1144 # in the final report.
1146 # @param self: The object pointer
1147 # @param FdRegion The current FdRegion object
1148 # @param Wa Workspace context information
1150 def __init__(self
, FdRegion
, Wa
):
1151 self
.Type
= FdRegion
.RegionType
1152 self
.BaseAddress
= FdRegion
.Offset
1153 self
.Size
= FdRegion
.Size
1157 self
._FvDir
= Wa
.FvDir
1160 # If the input FdRegion is not a firmware volume,
1163 if self
.Type
!= "FV":
1167 # Find all nested FVs in the FdRegion
1169 for FvName
in FdRegion
.RegionDataList
:
1170 if FvName
in self
.FvList
:
1172 self
.FvList
.append(FvName
)
1173 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1174 self
._DiscoverNestedFvList
(FvName
, Wa
)
1179 # Collect PCDs declared in DEC files.
1181 for Package
in Wa
.BuildDatabase
.WorkspaceDb
.PackageList
:
1182 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1183 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1184 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1186 # Collect PCDs defined in DSC common section
1188 for Platform
in Wa
.BuildDatabase
.WorkspaceDb
.PlatformList
:
1189 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
1190 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1191 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1194 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1196 self
._GuidsDb
["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
1197 self
._GuidsDb
["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"
1199 # Add ACPI table storage file
1201 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1203 for Pa
in Wa
.AutoGenObjectList
:
1204 for ModuleKey
in Pa
.Platform
.Modules
:
1205 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1206 InfPath
= os
.path
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1207 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1210 # Collect the GUID map in the FV firmware volume
1212 for FvName
in self
.FvList
:
1213 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1216 # collect GUID map for binary EFI file in FDF file.
1218 Guid
= Ffs
.NameGuid
.upper()
1219 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1221 PcdTokenspace
= Match
.group(1)
1222 PcdToken
= Match
.group(2)
1223 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1224 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1225 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1226 for Section
in Ffs
.SectionList
:
1228 ModuleSectFile
= os
.path
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1229 self
._GuidsDb
[Guid
] = ModuleSectFile
1230 except AttributeError:
1232 except AttributeError:
1237 # Internal worker function to generate report for the FD region
1239 # This internal worker function to generate report for the FD region.
1240 # It the type is firmware volume, it lists offset and module identification.
1242 # @param self The object pointer
1243 # @param File The file object for report
1244 # @param Title The title for the FD subsection
1245 # @param BaseAddress The base address for the FD region
1246 # @param Size The size of the FD region
1247 # @param FvName The FV name if the FD region is a firmware volume
1249 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1250 FileWrite(File
, gSubSectionStart
)
1251 FileWrite(File
, Title
)
1252 FileWrite(File
, "Type: %s" % Type
)
1253 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1255 if self
.Type
== "FV":
1259 FvReportFileName
= os
.path
.join(self
._FvDir
, FvName
+ ".fv.txt")
1262 # Collect size info in the firmware volume.
1264 FvReport
= open(FvReportFileName
).read()
1265 Match
= gFvTotalSizePattern
.search(FvReport
)
1267 FvTotalSize
= int(Match
.group(1), 16)
1268 Match
= gFvTakenSizePattern
.search(FvReport
)
1270 FvTakenSize
= int(Match
.group(1), 16)
1271 FvFreeSize
= FvTotalSize
- FvTakenSize
1273 # Write size information to the report file.
1275 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1276 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1277 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1278 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1279 FileWrite(File
, "Offset Module")
1280 FileWrite(File
, gSubSectionSep
)
1282 # Write module offset and module identification to the report file.
1285 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1286 Guid
= Match
.group(2).upper()
1287 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1288 OffsetList
= OffsetInfo
.keys()
1290 for Offset
in OffsetList
:
1291 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1293 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1295 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1296 FileWrite(File
, gSubSectionEnd
)
1299 # Generate report for the FD region
1301 # This function generates report for the FD region.
1303 # @param self The object pointer
1304 # @param File The file object for report
1306 def GenerateReport(self
, File
):
1307 if (len(self
.FvList
) > 0):
1308 for FvItem
in self
.FvList
:
1309 Info
= self
.FvInfo
[FvItem
]
1310 self
._GenerateReport
(File
, Info
[0], "FV", Info
[1], Info
[2], FvItem
)
1312 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
1315 # Reports FD information
1317 # This class reports the FD section in the build report file.
1318 # It collects flash device information for a platform.
1320 class FdReport(object):
1322 # Constructor function for class FdReport
1324 # This constructor function generates FdReport object for a specified
1327 # @param self The object pointer
1328 # @param Fd The current Firmware device object
1329 # @param Wa Workspace context information
1331 def __init__(self
, Fd
, Wa
):
1332 self
.FdName
= Fd
.FdUiName
1333 self
.BaseAddress
= Fd
.BaseAddress
1335 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
1338 # Generate report for the firmware device.
1340 # This function generates report for the firmware device.
1342 # @param self The object pointer
1343 # @param File The file object for report
1345 def GenerateReport(self
, File
):
1346 FileWrite(File
, gSectionStart
)
1347 FileWrite(File
, "Firmware Device (FD)")
1348 FileWrite(File
, "FD Name: %s" % self
.FdName
)
1349 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
1350 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
1351 if len(self
.FdRegionList
) > 0:
1352 FileWrite(File
, gSectionSep
)
1353 for FdRegionItem
in self
.FdRegionList
:
1354 FdRegionItem
.GenerateReport(File
)
1356 FileWrite(File
, gSectionEnd
)
1361 # Reports platform information
1363 # This class reports the whole platform information
1365 class PlatformReport(object):
1367 # Constructor function for class PlatformReport
1369 # This constructor function generates PlatformReport object a platform build.
1370 # It generates report for platform summary, flash, global PCDs and detailed
1371 # module information for modules involved in platform build.
1373 # @param self The object pointer
1374 # @param Wa Workspace context information
1375 # @param MaList The list of modules in the platform build
1377 def __init__(self
, Wa
, MaList
, ReportType
):
1378 self
._WorkspaceDir
= Wa
.WorkspaceDir
1379 self
.PlatformName
= Wa
.Name
1380 self
.PlatformDscPath
= Wa
.Platform
1381 self
.Architectures
= " ".join(Wa
.ArchList
)
1382 self
.ToolChain
= Wa
.ToolChain
1383 self
.Target
= Wa
.BuildTarget
1384 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
1385 self
.BuildEnvironment
= platform
.platform()
1387 self
.PcdReport
= None
1388 if "PCD" in ReportType
:
1389 self
.PcdReport
= PcdReport(Wa
)
1391 self
.FdReportList
= []
1392 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
== None:
1393 for Fd
in Wa
.FdfProfile
.FdDict
:
1394 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
1396 self
.PredictionReport
= None
1397 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
1398 self
.PredictionReport
= PredictionReport(Wa
)
1400 self
.DepexParser
= None
1401 if "DEPEX" in ReportType
:
1402 self
.DepexParser
= DepexParser(Wa
)
1404 self
.ModuleReportList
= []
1406 self
._IsModuleBuild
= True
1408 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
1410 self
._IsModuleBuild
= False
1411 for Pa
in Wa
.AutoGenObjectList
:
1412 for ModuleKey
in Pa
.Platform
.Modules
:
1413 self
.ModuleReportList
.append(ModuleReport(Pa
.Platform
.Modules
[ModuleKey
].M
, ReportType
))
1418 # Generate report for the whole platform.
1420 # This function generates report for platform information.
1421 # It comprises of platform summary, global PCD, flash and
1422 # module list sections.
1424 # @param self The object pointer
1425 # @param File The file object for report
1426 # @param BuildDuration The total time to build the modules
1427 # @param ReportType The kind of report items in the final report file
1429 def GenerateReport(self
, File
, BuildDuration
, ReportType
):
1430 FileWrite(File
, "Platform Summary")
1431 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
1432 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
1433 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
1434 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
1435 FileWrite(File
, "Target: %s" % self
.Target
)
1436 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
1437 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
1438 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
1439 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
1441 if not self
._IsModuleBuild
:
1442 if "PCD" in ReportType
:
1443 self
.PcdReport
.GenerateReport(File
, None)
1445 if "FLASH" in ReportType
:
1446 for FdReportListItem
in self
.FdReportList
:
1447 FdReportListItem
.GenerateReport(File
)
1449 for ModuleReportItem
in self
.ModuleReportList
:
1450 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
1452 if not self
._IsModuleBuild
:
1453 if "EXECUTION_ORDER" in ReportType
:
1454 self
.PredictionReport
.GenerateReport(File
, None)
1456 ## BuildReport class
1458 # This base class contain the routines to collect data and then
1459 # applies certain format to the output report
1461 class BuildReport(object):
1463 # Constructor function for class BuildReport
1465 # This constructor function generates BuildReport object a platform build.
1466 # It generates report for platform summary, flash, global PCDs and detailed
1467 # module information for modules involved in platform build.
1469 # @param self The object pointer
1470 # @param ReportFile The file name to save report file
1471 # @param ReportType The kind of report items in the final report file
1473 def __init__(self
, ReportFile
, ReportType
):
1474 self
.ReportFile
= ReportFile
1476 self
.ReportList
= []
1477 self
.ReportType
= []
1479 for ReportTypeItem
in ReportType
:
1480 if ReportTypeItem
not in self
.ReportType
:
1481 self
.ReportType
.append(ReportTypeItem
)
1483 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "FLASH", "FIXED_ADDRESS"]
1485 # Adds platform report to the list
1487 # This function adds a platform report to the final report list.
1489 # @param self The object pointer
1490 # @param Wa Workspace context information
1491 # @param MaList The list of modules in the platform build
1493 def AddPlatformReport(self
, Wa
, MaList
=None):
1495 self
.ReportList
.append((Wa
, MaList
))
1498 # Generates the final report.
1500 # This function generates platform build report. It invokes GenerateReport()
1501 # method for every platform report in the list.
1503 # @param self The object pointer
1504 # @param BuildDuration The total time to build the modules
1506 def GenerateReport(self
, BuildDuration
):
1510 for (Wa
, MaList
) in self
.ReportList
:
1511 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, self
.ReportType
)
1512 SaveFileOnChange(self
.ReportFile
, File
.getvalue(), False)
1513 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
1515 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
1517 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
1518 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1521 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1522 if __name__
== '__main__':