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
8 # All rights reserved. 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.
25 from datetime
import datetime
26 from Common
import EdkLogger
27 from Common
.Misc
import GuidStructureByteArrayToGuidString
28 from Common
.Misc
import GuidStructureStringToGuidString
29 from Common
.InfClassObject
import gComponentType2ModuleType
30 from Common
.BuildToolError
import FILE_OPEN_FAILURE
31 from Common
.BuildToolError
import FILE_WRITE_FAILURE
32 from Common
.BuildToolError
import CODE_ERROR
35 ## Pattern to extract contents in EDK DXS files
36 gDxsDependencyPattern
= re
.compile(r
"DEPENDENCY_START(.+)DEPENDENCY_END", re
.DOTALL
)
38 ## Pattern to find total FV total size, occupied size in flash report intermediate file
39 gFvTotalSizePattern
= re
.compile(r
"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
40 gFvTakenSizePattern
= re
.compile(r
"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
42 ## Pattern to find module size and time stamp in module summary report intermediate file
43 gModuleSizePattern
= re
.compile(r
"MODULE_SIZE = (\d+)")
44 gTimeStampPattern
= re
.compile(r
"TIME_STAMP = (\d+)")
46 ## Pattern to find GUID value in flash description files
47 gPcdGuidPattern
= re
.compile(r
"PCD\((\w+)[.](\w+)\)")
49 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
50 gOffsetGuidPattern
= re
.compile(r
"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
52 ## Pattern to find module base address and entry point in fixed flash map file
53 gModulePattern
= r
"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
54 gMapFileItemPattern
= re
.compile(gModulePattern
% {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
56 ## Pattern to find all module referenced header files in source files
57 gIncludePattern
= re
.compile(r
'#include\s*["<]([^">]+)[">]')
58 gIncludePattern2
= re
.compile(r
"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
60 ## Pattern to find the entry point for EDK module using EDKII Glue library
61 gGlueLibEntryPoint
= re
.compile(r
"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
63 ## Tags for section start, end and separator
64 gSectionStart
= ">" + "=" * 118 + "<"
65 gSectionEnd
= "<" + "=" * 118 + ">" + "\n"
66 gSectionSep
= "=" * 120
68 ## Tags for subsection start, end and separator
69 gSubSectionStart
= ">" + "-" * 118 + "<"
70 gSubSectionEnd
= "<" + "-" * 118 + ">"
71 gSubSectionSep
= "-" * 120
73 ## The look up table to map PCD type to pair of report display type and DEC type
75 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),
76 'PatchableInModule': ('PATCH', 'PatchableInModule'),
77 'FeatureFlag' : ('FLAG', 'FeatureFlag'),
78 'Dynamic' : ('DYN', 'Dynamic'),
79 'DynamicHii' : ('DYNHII', 'Dynamic'),
80 'DynamicVpd' : ('DYNVPD', 'Dynamic'),
81 'DynamicEx' : ('DEX', 'Dynamic'),
82 'DynamicExHii' : ('DEXHII', 'Dynamic'),
83 'DynamicExVpd' : ('DEXVPD', 'Dynamic'),
86 ## The look up table to map module type to driver type
88 'SEC' : '0x3 (SECURITY_CORE)',
89 'PEI_CORE' : '0x4 (PEI_CORE)',
90 'PEIM' : '0x6 (PEIM)',
91 'DXE_CORE' : '0x5 (DXE_CORE)',
92 'DXE_DRIVER' : '0x7 (DRIVER)',
93 'DXE_SAL_DRIVER' : '0x7 (DRIVER)',
94 'DXE_SMM_DRIVER' : '0x7 (DRIVER)',
95 'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',
96 'UEFI_DRIVER' : '0x7 (DRIVER)',
97 'UEFI_APPLICATION' : '0x9 (APPLICATION)',
98 'SMM_CORE' : '0xD (SMM_CORE)',
99 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
103 # Writes a string to the file object.
105 # This function writes a string to the file object and a new line is appended
106 # afterwards. It may optionally wraps the string for better readability.
108 # @File The file object to write
109 # @String The string to be written to the file
110 # @Wrapper Indicates whether to wrap the string
112 def FileWrite(File
, String
, Wrapper
=False):
114 String
= textwrap
.fill(String
, 120)
115 File
.write(String
+ "\r\n")
118 # Find all the header file that the module source directly includes.
120 # This function scans source code to find all header files the module may
121 # include. This is not accurate but very effective to find all the header
122 # file the module might include with #include statement.
124 # @Source The source file name
125 # @IncludePathList The list of include path to find the source file.
126 # @IncludeFiles The dictionary of current found include files.
128 def FindIncludeFiles(Source
, IncludePathList
, IncludeFiles
):
129 FileContents
= open(Source
).read()
131 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
133 for Match
in gIncludePattern
.finditer(FileContents
):
134 FileName
= Match
.group(1).strip()
135 for Dir
in [os
.path
.dirname(Source
)] + IncludePathList
:
136 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
137 if os
.path
.exists(FullFileName
):
138 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
142 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
144 for Match
in gIncludePattern2
.finditer(FileContents
):
146 Type
= Match
.group(1)
147 if "ARCH_PROTOCOL" in Type
:
148 FileName
= "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
149 elif "PROTOCOL" in Type
:
150 FileName
= "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
152 FileName
= "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key
}
154 FileName
= "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key
}
157 for Dir
in IncludePathList
:
158 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
159 if os
.path
.exists(FullFileName
):
160 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
164 # Reports library information
166 # This class reports the module library subsection in the build report file.
168 class LibraryReport(object):
170 # Constructor function for class LibraryReport
172 # This constructor function generates LibraryReport object for
175 # @param self The object pointer
176 # @param M Module context information
178 def __init__(self
, M
):
179 self
.LibraryList
= []
180 if int(str(M
.AutoGenVersion
), 0) >= 0x00010005:
181 self
._EdkIIModule
= True
183 self
._EdkIIModule
= False
185 for Lib
in M
.DependentLibraryList
:
186 LibInfPath
= str(Lib
)
187 LibClassList
= Lib
.LibraryClass
[0].LibraryClass
188 LibConstructorList
= Lib
.ConstructorList
189 LibDesstructorList
= Lib
.DestructorList
190 LibDepexList
= Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]
191 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
))
194 # Generate report for module library information
196 # This function generates report for the module library.
197 # If the module is EDKII style one, the additional library class, library
198 # constructor/destructor and dependency expression may also be reported.
200 # @param self The object pointer
201 # @param File The file object for report
203 def GenerateReport(self
, File
):
204 FileWrite(File
, gSubSectionStart
)
205 FileWrite(File
, "Library")
206 if len(self
.LibraryList
) > 0:
207 FileWrite(File
, gSubSectionSep
)
208 for LibraryItem
in self
.LibraryList
:
209 LibInfPath
= LibraryItem
[0]
210 FileWrite(File
, LibInfPath
)
213 # Report library class, library constructor and destructor for
214 # EDKII style module.
216 if self
._EdkIIModule
:
217 LibClass
= LibraryItem
[1]
219 LibConstructor
= " ".join(LibraryItem
[2])
221 EdkIILibInfo
+= " C = " + LibConstructor
222 LibDestructor
= " ".join(LibraryItem
[3])
224 EdkIILibInfo
+= " D = " + LibConstructor
225 LibDepex
= " ".join(LibraryItem
[4])
227 EdkIILibInfo
+= " Depex = " + LibDepex
229 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
231 FileWrite(File
, "{%s}" % LibClass
)
233 FileWrite(File
, gSubSectionEnd
)
236 # Reports dependency expression information
238 # This class reports the module dependency expression subsection in the build report file.
240 class DepexReport(object):
242 # Constructor function for class DepexReport
244 # This constructor function generates DepexReport object for
245 # a module. If the module source contains the DXS file (usually EDK
246 # style module), it uses the dependency in DXS file; otherwise,
247 # it uses the dependency expression from its own INF [Depex] section
248 # and then merges with the ones from its dependent library INF.
250 # @param self The object pointer
251 # @param M Module context information
253 def __init__(self
, M
):
255 ModuleType
= M
.ModuleType
257 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
258 if ModuleType
in ["SEC", "PEI_CORE", "DXE_CORE"]:
261 for Source
in M
.SourceFileList
:
262 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
263 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
265 self
.Depex
= Match
.group(1).strip()
269 self
.Depex
= M
.DepexExpressionList
.get(M
.ModuleType
, "")
270 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
271 if not self
.ModuleDepex
:
272 self
.ModuleDepex
= "(None)"
275 for Lib
in M
.DependentLibraryList
:
276 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
278 LibDepexList
.append("(" + LibDepex
+ ")")
279 self
.LibraryDepex
= " AND ".join(LibDepexList
)
280 if not self
.LibraryDepex
:
281 self
.LibraryDepex
= "(None)"
285 # Generate report for module dependency expression information
287 # This function generates report for the module dependency expression.
289 # @param self The object pointer
290 # @param File The file object for report
292 def GenerateReport(self
, File
):
296 FileWrite(File
, gSubSectionStart
)
297 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
299 if self
.Source
== "INF":
300 FileWrite(File
, "%s" % self
.Depex
, True)
301 FileWrite(File
, gSubSectionSep
)
302 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
303 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
305 FileWrite(File
, "%s" % self
.Depex
)
306 FileWrite(File
, gSubSectionEnd
)
309 # Reports dependency expression information
311 # This class reports the module build flags subsection in the build report file.
313 class BuildFlagsReport(object):
315 # Constructor function for class BuildFlagsReport
317 # This constructor function generates BuildFlagsReport object for
318 # a module. It reports the build tool chain tag and all relevant
319 # build flags to build the module.
321 # @param self The object pointer
322 # @param M Module context information
324 def __init__(self
, M
):
327 # Add build flags according to source file extension so that
328 # irrelevant ones can be filtered out.
330 for Source
in M
.SourceFileList
:
331 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
332 if Ext
in [".c", ".cc", ".cpp"]:
333 BuildOptions
["CC"] = 1
334 elif Ext
in [".s", ".asm"]:
335 BuildOptions
["PP"] = 1
336 BuildOptions
["ASM"] = 1
337 elif Ext
in [".vfr"]:
338 BuildOptions
["VFRPP"] = 1
339 BuildOptions
["VFR"] = 1
340 elif Ext
in [".dxs"]:
341 BuildOptions
["APP"] = 1
342 BuildOptions
["CC"] = 1
343 elif Ext
in [".asl"]:
344 BuildOptions
["ASLPP"] = 1
345 BuildOptions
["ASL"] = 1
346 elif Ext
in [".aslc"]:
347 BuildOptions
["ASLCC"] = 1
348 BuildOptions
["ASLDLINK"] = 1
349 BuildOptions
["CC"] = 1
350 elif Ext
in [".asm16"]:
351 BuildOptions
["ASMLINK"] = 1
352 BuildOptions
["SLINK"] = 1
353 BuildOptions
["DLINK"] = 1
356 # Save module build flags.
358 self
.ToolChainTag
= M
.ToolChain
360 for Tool
in BuildOptions
:
361 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
364 # Generate report for module build flags information
366 # This function generates report for the module build flags expression.
368 # @param self The object pointer
369 # @param File The file object for report
371 def GenerateReport(self
, File
):
372 FileWrite(File
, gSubSectionStart
)
373 FileWrite(File
, "Build Flags")
374 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
375 for Tool
in self
.BuildFlags
:
376 FileWrite(File
, gSubSectionSep
)
377 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
379 FileWrite(File
, gSubSectionEnd
)
383 # Reports individual module information
385 # This class reports the module section in the build report file.
386 # It comprises of module summary, module PCD, library, dependency expression,
387 # build flags sections.
389 class ModuleReport(object):
391 # Constructor function for class ModuleReport
393 # This constructor function generates ModuleReport object for
394 # a separate module in a platform build.
396 # @param self The object pointer
397 # @param M Module context information
398 # @param ReportType The kind of report items in the final report file
400 def __init__(self
, M
, ReportType
):
401 self
.ModuleName
= M
.Module
.BaseName
402 self
.ModuleInfPath
= M
.MetaFile
.File
403 self
.FileGuid
= M
.Guid
405 self
.BuildTimeStamp
= None
407 ModuleType
= M
.ModuleType
409 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
411 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
413 if ModuleType
== "DXE_SMM_DRIVER":
414 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
415 if int(PiSpec
, 0) >= 0x0001000A:
416 ModuleType
= "SMM_DRIVER"
417 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "")
418 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
419 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
420 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
421 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
422 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
424 self
._BuildDir
= M
.BuildDir
425 self
.ModulePcdSet
= {}
426 if "PCD" in ReportType
:
428 # Collect all module used PCD set: module INF referenced directly or indirectly.
429 # It also saves module INF default values of them in case they exist.
431 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
432 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
434 self
.LibraryReport
= None
435 if "LIBRARY" in ReportType
:
436 self
.LibraryReport
= LibraryReport(M
)
438 self
.DepexReport
= None
439 if "DEPEX" in ReportType
:
440 self
.DepexReport
= DepexReport(M
)
442 if "BUILD_FLAGS" in ReportType
:
443 self
.BuildFlagsReport
= BuildFlagsReport(M
)
447 # Generate report for module information
449 # This function generates report for separate module expression
450 # in a platform build.
452 # @param self The object pointer
453 # @param File The file object for report
454 # @param GlobalPcdReport The platform global PCD class object
455 # @param ReportType The kind of report items in the final report file
457 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, ReportType
):
458 FileWrite(File
, gSectionStart
)
460 FwReportFileName
= os
.path
.join(self
._BuildDir
, "DEBUG", self
.ModuleName
+ ".txt")
461 if os
.path
.isfile(FwReportFileName
):
463 FileContents
= open(FwReportFileName
).read()
464 Match
= gModuleSizePattern
.search(FileContents
)
466 self
.Size
= int(Match
.group(1))
468 Match
= gTimeStampPattern
.search(FileContents
)
470 self
.BuildTimeStamp
= datetime
.fromtimestamp(int(Match
.group(1)))
472 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
474 FileWrite(File
, "Module Summary")
475 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
476 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
477 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
479 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
480 if self
.BuildTimeStamp
:
481 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
483 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
484 if self
.UefiSpecVersion
:
485 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
486 if self
.PiSpecVersion
:
487 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
489 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
491 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
492 if self
.PciClassCode
:
493 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
495 FileWrite(File
, gSectionSep
)
497 if "PCD" in ReportType
:
498 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
500 if "LIBRARY" in ReportType
:
501 self
.LibraryReport
.GenerateReport(File
)
503 if "DEPEX" in ReportType
:
504 self
.DepexReport
.GenerateReport(File
)
506 if "BUILD_FLAGS" in ReportType
:
507 self
.BuildFlagsReport
.GenerateReport(File
)
509 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
510 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
512 FileWrite(File
, gSectionEnd
)
515 # Reports platform and module PCD information
517 # This class reports the platform PCD section and module PCD subsection
518 # in the build report file.
520 class PcdReport(object):
522 # Constructor function for class PcdReport
524 # This constructor function generates PcdReport object a platform build.
525 # It collects the whole PCD database from platform DSC files, platform
526 # flash description file and package DEC files.
528 # @param self The object pointer
529 # @param Wa Workspace context information
531 def __init__(self
, Wa
):
535 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
539 self
.ModulePcdOverride
= {}
540 for Pa
in Wa
.AutoGenObjectList
:
542 # Collect all platform referenced PCDs and grouped them by PCD token space
545 for Pcd
in Pa
.AllPcdList
:
546 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
547 if Pcd
not in PcdList
:
549 if len(Pcd
.TokenCName
) > self
.MaxLen
:
550 self
.MaxLen
= len(Pcd
.TokenCName
)
552 for Module
in Pa
.Platform
.Modules
.values():
554 # Collect module override PCDs
556 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
557 TokenCName
= ModulePcd
.TokenCName
558 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
559 ModuleDefault
= ModulePcd
.DefaultValue
560 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
561 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
565 # Collect PCD DEC default value.
567 self
.DecPcdDefault
= {}
568 for Package
in Wa
.BuildDatabase
.WorkspaceDb
.PackageList
:
569 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
570 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
571 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
573 # Collect PCDs defined in DSC common section
575 self
.DscPcdDefault
= {}
576 for Platform
in Wa
.BuildDatabase
.WorkspaceDb
.PlatformList
:
577 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
578 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
579 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
582 # Generate report for PCD information
584 # This function generates report for separate module expression
585 # in a platform build.
587 # @param self The object pointer
588 # @param File The file object for report
589 # @param ModulePcdSet Set of all PCDs referenced by module or None for
590 # platform PCD report
591 # @param DscOverridePcds Module DSC override PCDs set
593 def GenerateReport(self
, File
, ModulePcdSet
):
594 if ModulePcdSet
== None:
596 # For platform global PCD section
598 FileWrite(File
, gSectionStart
)
599 FileWrite(File
, "Platform Configuration Database Report")
600 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
601 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
602 FileWrite(File
, " *M - Module scoped PCD override in DSC file")
603 FileWrite(File
, gSectionSep
)
606 # For module PCD sub-section
608 FileWrite(File
, gSubSectionStart
)
609 FileWrite(File
, "PCD")
610 FileWrite(File
, gSubSectionSep
)
612 for Key
in self
.AllPcds
:
614 # Group PCD by their token space GUID C Name
617 for Type
in self
.AllPcds
[Key
]:
619 # Group PCD by their usage type
621 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
622 for Pcd
in self
.AllPcds
[Key
][Type
]:
624 # Get PCD default value and their override relationship
626 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
627 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
628 DscDefaultValue
= self
.FdfPcdSet
.get((Pcd
.TokenCName
, Key
), DscDefaultValue
)
629 InfDefaultValue
= None
631 PcdValue
= DecDefaultValue
633 PcdValue
= DscDefaultValue
634 if ModulePcdSet
!= None:
635 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
637 InfDefault
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
641 if ModulePcdSet
== None:
647 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
648 PcdValueNumber
= int(PcdValue
.strip(), 0)
649 if DecDefaultValue
== None:
652 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
653 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
655 if InfDefaultValue
== None:
658 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
659 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
661 if DscDefaultValue
== None:
664 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
665 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
667 if DecDefaultValue
== None:
670 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
672 if InfDefaultValue
== None:
675 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
677 if DscDefaultValue
== None:
680 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
683 # Report PCD item according to their override relationship
685 if DecMatch
and InfMatch
:
686 FileWrite(File
, ' %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
689 if (Pcd
.TokenCName
, Key
) in self
.FdfPcdSet
:
690 FileWrite(File
, ' *F %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
692 FileWrite(File
, ' *P %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
694 FileWrite(File
, ' *M %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
696 if TypeName
in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):
697 for SkuInfo
in Pcd
.SkuInfoList
.values():
698 if TypeName
in ('DYNHII', 'DEXHII'):
699 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
701 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
703 if not DscMatch
and DscDefaultValue
!= None:
704 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', DscDefaultValue
.strip()))
706 if not InfMatch
and InfDefaultValue
!= None:
707 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', InfDefaultValue
.strip()))
709 if not DecMatch
and DecDefaultValue
!= None:
710 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', DecDefaultValue
.strip()))
712 if ModulePcdSet
== None:
713 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
714 for ModulePath
in ModuleOverride
:
715 ModuleDefault
= ModuleOverride
[ModulePath
]
716 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
717 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
718 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
720 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
723 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 19, ModulePath
, ModuleDefault
.strip()))
725 if ModulePcdSet
== None:
726 FileWrite(File
, gSectionEnd
)
728 FileWrite(File
, gSubSectionEnd
)
733 # Reports platform and module Prediction information
735 # This class reports the platform execution order prediction section and
736 # module load fixed address prediction subsection in the build report file.
738 class PredictionReport(object):
740 # Constructor function for class PredictionReport
742 # This constructor function generates PredictionReport object for the platform.
744 # @param self: The object pointer
745 # @param Wa Workspace context information
747 def __init__(self
, Wa
):
748 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
749 self
._MapFileParsed
= False
750 self
._EotToolInvoked
= False
751 self
._FvDir
= Wa
.FvDir
752 self
._EotDir
= Wa
.BuildDir
753 self
._FfsEntryPoint
= {}
755 self
._SourceList
= []
756 self
.FixedMapDict
= {}
761 # Collect all platform reference source files and GUID C Name
763 for Pa
in Wa
.AutoGenObjectList
:
764 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
766 # Add module referenced source files
768 self
._SourceList
.append(str(Module
))
770 for Source
in Module
.SourceFileList
:
771 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
772 self
._SourceList
.append(" " + str(Source
))
773 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
774 for IncludeFile
in IncludeList
.values():
775 self
._SourceList
.append(" " + IncludeFile
)
777 for Guid
in Module
.PpiList
:
778 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
779 for Guid
in Module
.ProtocolList
:
780 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
781 for Guid
in Module
.GuidList
:
782 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
784 if Module
.Guid
and not Module
.IsLibrary
:
785 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
786 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
787 RealEntryPoint
= "_ModuleEntryPoint"
789 RealEntryPoint
= EntryPoint
790 if EntryPoint
== "_ModuleEntryPoint":
791 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
792 Match
= gGlueLibEntryPoint
.search(CCFlags
)
794 EntryPoint
= Match
.group(1)
796 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
800 # Collect platform firmware volume list as the input of EOT.
804 for Fd
in Wa
.FdfProfile
.FdDict
:
805 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
806 if FdRegion
.RegionType
!= "FV":
808 for FvName
in FdRegion
.RegionDataList
:
809 if FvName
in self
._FvList
:
811 self
._FvList
.append(FvName
)
812 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
813 for Section
in Ffs
.SectionList
:
815 for FvSection
in Section
.SectionList
:
816 if FvSection
.FvName
in self
._FvList
:
818 self
._FvList
.append(FvSection
.FvName
)
819 except AttributeError:
824 # Parse platform fixed address map files
826 # This function parses the platform final fixed address map file to get
827 # the database of predicted fixed address for module image base, entry point
830 # @param self: The object pointer
832 def _ParseMapFile(self
):
833 if self
._MapFileParsed
:
835 self
._MapFileParsed
= True
836 if os
.path
.isfile(self
._MapFileName
):
838 FileContents
= open(self
._MapFileName
).read()
839 for Match
in gMapFileItemPattern
.finditer(FileContents
):
840 AddressType
= Match
.group(1)
841 BaseAddress
= Match
.group(2)
842 EntryPoint
= Match
.group(3)
843 Guid
= Match
.group(4).upper()
844 List
= self
.FixedMapDict
.setdefault(Guid
, [])
845 List
.append((AddressType
, BaseAddress
, "*I"))
846 List
.append((AddressType
, EntryPoint
, "*E"))
848 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
851 # Invokes EOT tool to get the predicted the execution order.
853 # This function invokes EOT tool to calculate the predicted dispatch order
855 # @param self: The object pointer
857 def _InvokeEotTool(self
):
858 if self
._EotToolInvoked
:
861 self
._EotToolInvoked
= True
863 for FvName
in self
._FvList
:
864 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
865 if os
.path
.isfile(FvFile
):
866 FvFileList
.append(FvFile
)
868 if len(FvFileList
) == 0:
871 # Write source file list and GUID file list to an intermediate file
872 # as the input for EOT tool and dispatch List as the output file
875 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
876 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
877 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
879 TempFile
= open(SourceList
, "w+")
880 for Item
in self
._SourceList
:
881 FileWrite(TempFile
, Item
)
883 TempFile
= open(GuidList
, "w+")
884 for Key
in self
._GuidMap
:
885 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
889 from Eot
.Eot
import Eot
893 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
894 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
897 # Parse the output of EOT tool
899 for Line
in open(DispatchList
):
900 if len(Line
.split()) < 4:
902 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
903 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
904 if len(Symbol
) > self
.MaxLen
:
905 self
.MaxLen
= len(Symbol
)
906 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
908 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
909 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
913 # Generate platform execution order report
915 # This function generates the predicted module execution order.
917 # @param self The object pointer
918 # @param File The file object for report
920 def _GenerateExecutionOrderReport(self
, File
):
921 self
._InvokeEotTool
()
922 if len(self
.ItemList
) == 0:
924 FileWrite(File
, gSectionStart
)
925 FileWrite(File
, "Execution Order Prediction")
926 FileWrite(File
, "*P PEI phase")
927 FileWrite(File
, "*D DXE phase")
928 FileWrite(File
, "*E Module INF entry point name")
929 FileWrite(File
, "*N Module notification function name")
931 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
932 FileWrite(File
, gSectionSep
)
933 for Item
in self
.ItemList
:
934 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
936 FileWrite(File
, gSectionStart
)
939 # Generate Fixed Address report.
941 # This function generate the predicted fixed address report for a module
944 # @param self The object pointer
945 # @param File The file object for report
946 # @param Guid The module Guid value.
947 # @param NotifyList The list of all notify function in a module
949 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
951 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
952 if not FixedAddressList
:
955 FileWrite(File
, gSubSectionStart
)
956 FileWrite(File
, "Fixed Address Prediction")
957 FileWrite(File
, "*I Image Loading Address")
958 FileWrite(File
, "*E Entry Point Address")
959 FileWrite(File
, "*N Notification Function Address")
960 FileWrite(File
, "*F Flash Address")
961 FileWrite(File
, "*M Memory Address")
962 FileWrite(File
, "*S SMM RAM Offset")
963 FileWrite(File
, "TOM Top of Memory")
965 FileWrite(File
, "Type Address Name")
966 FileWrite(File
, gSubSectionSep
)
967 for Item
in FixedAddressList
:
972 Name
= "(Image Base)"
974 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
975 elif Symbol
in NotifyList
:
983 elif "Memory" in Type
:
989 Value
= "TOM" + Value
991 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
994 # Generate report for the prediction part
996 # This function generate the predicted fixed address report for a module or
997 # predicted module execution order for a platform.
998 # If the input Guid is None, then, it generates the predicted module execution order;
999 # otherwise it generated the module fixed loading address for the module specified by
1002 # @param self The object pointer
1003 # @param File The file object for report
1004 # @param Guid The module Guid value.
1006 def GenerateReport(self
, File
, Guid
):
1008 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1010 self
._GenerateExecutionOrderReport
(File
)
1013 # Reports FD region information
1015 # This class reports the FD subsection in the build report file.
1016 # It collects region information of platform flash device.
1017 # If the region is a firmware volume, it lists the set of modules
1018 # and its space information; otherwise, it only lists its region name,
1019 # base address and size in its sub-section header.
1020 # If there are nesting FVs, the nested FVs will list immediate after
1021 # this FD region subsection
1023 class FdRegionReport(object):
1025 # Discover all the nested FV name list.
1027 # This is an internal worker function to discover the all the nested FV information
1028 # in the parent firmware volume. It uses deep first search algorithm recursively to
1029 # find all the FV list name and append them to the list.
1031 # @param self The object pointer
1032 # @param FvName The name of current firmware file system
1033 # @param Wa Workspace context information
1035 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1036 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1037 for Section
in Ffs
.SectionList
:
1039 for FvSection
in Section
.SectionList
:
1040 if FvSection
.FvName
in self
.FvList
:
1042 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1043 self
.FvList
.append(FvSection
.FvName
)
1044 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1045 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1046 except AttributeError:
1050 # Constructor function for class FdRegionReport
1052 # This constructor function generates FdRegionReport object for a specified FdRegion.
1053 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1054 # volume list. This function also collects GUID map in order to dump module identification
1055 # in the final report.
1057 # @param self: The object pointer
1058 # @param FdRegion The current FdRegion object
1059 # @param Wa Workspace context information
1061 def __init__(self
, FdRegion
, Wa
):
1062 self
.Type
= FdRegion
.RegionType
1063 self
.BaseAddress
= FdRegion
.Offset
1064 self
.Size
= FdRegion
.Size
1068 self
._FvDir
= Wa
.FvDir
1071 # If the input FdRegion is not a firmware volume,
1074 if self
.Type
!= "FV":
1078 # Find all nested FVs in the FdRegion
1080 for FvName
in FdRegion
.RegionDataList
:
1081 if FvName
in self
.FvList
:
1083 self
.FvList
.append(FvName
)
1084 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1085 self
._DiscoverNestedFvList
(FvName
, Wa
)
1090 # Collect PCDs declared in DEC files.
1092 for Package
in Wa
.BuildDatabase
.WorkspaceDb
.PackageList
:
1093 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1094 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1095 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1097 # Collect PCDs defined in DSC common section
1099 for Platform
in Wa
.BuildDatabase
.WorkspaceDb
.PlatformList
:
1100 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
1101 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1102 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1105 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1107 self
._GuidsDb
["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
1108 self
._GuidsDb
["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"
1110 # Add ACPI table storage file
1112 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1114 for Pa
in Wa
.AutoGenObjectList
:
1115 for ModuleKey
in Pa
.Platform
.Modules
:
1116 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1117 InfPath
= os
.path
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1118 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1121 # Collect the GUID map in the FV firmware volume
1123 for FvName
in self
.FvList
:
1124 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1127 # collect GUID map for binary EFI file in FDF file.
1129 Guid
= Ffs
.NameGuid
.upper()
1130 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1132 PcdTokenspace
= Match
.group(1)
1133 PcdToken
= Match
.group(2)
1134 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1135 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1136 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1137 for Section
in Ffs
.SectionList
:
1139 ModuleSectFile
= os
.path
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1140 self
._GuidsDb
[Guid
] = ModuleSectFile
1141 except AttributeError:
1143 except AttributeError:
1148 # Internal worker function to generate report for the FD region
1150 # This internal worker function to generate report for the FD region.
1151 # It the type is firmware volume, it lists offset and module identification.
1153 # @param self The object pointer
1154 # @param File The file object for report
1155 # @param Title The title for the FD subsection
1156 # @param BaseAddress The base address for the FD region
1157 # @param Size The size of the FD region
1158 # @param FvName The FV name if the FD region is a firmware volume
1160 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1161 FileWrite(File
, gSubSectionStart
)
1162 FileWrite(File
, Title
)
1163 FileWrite(File
, "Type: %s" % Type
)
1164 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1166 if self
.Type
== "FV":
1170 FvReportFileName
= os
.path
.join(self
._FvDir
, FvName
+ ".fv.txt")
1173 # Collect size info in the firmware volume.
1175 FvReport
= open(FvReportFileName
).read()
1176 Match
= gFvTotalSizePattern
.search(FvReport
)
1178 FvTotalSize
= int(Match
.group(1), 16)
1179 Match
= gFvTakenSizePattern
.search(FvReport
)
1181 FvTakenSize
= int(Match
.group(1), 16)
1182 FvFreeSize
= FvTotalSize
- FvTakenSize
1184 # Write size information to the report file.
1186 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1187 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1188 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1189 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1190 FileWrite(File
, "Offset Module")
1191 FileWrite(File
, gSubSectionSep
)
1193 # Write module offset and module identification to the report file.
1196 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1197 Guid
= Match
.group(2).upper()
1198 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1199 OffsetList
= OffsetInfo
.keys()
1201 for Offset
in OffsetList
:
1202 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1204 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1206 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1207 FileWrite(File
, gSubSectionEnd
)
1210 # Generate report for the FD region
1212 # This function generates report for the FD region.
1214 # @param self The object pointer
1215 # @param File The file object for report
1217 def GenerateReport(self
, File
):
1218 if (len(self
.FvList
) > 0):
1219 for FvItem
in self
.FvList
:
1220 Info
= self
.FvInfo
[FvItem
]
1221 self
._GenerateReport
(File
, Info
[0], "FV", Info
[1], Info
[2], FvItem
)
1223 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
1226 # Reports FD information
1228 # This class reports the FD section in the build report file.
1229 # It collects flash device information for a platform.
1231 class FdReport(object):
1233 # Constructor function for class FdReport
1235 # This constructor function generates FdReport object for a specified
1238 # @param self The object pointer
1239 # @param Fd The current Firmware device object
1240 # @param Wa Workspace context information
1242 def __init__(self
, Fd
, Wa
):
1243 self
.FdName
= Fd
.FdUiName
1244 self
.BaseAddress
= Fd
.BaseAddress
1246 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
1249 # Generate report for the firmware device.
1251 # This function generates report for the firmware device.
1253 # @param self The object pointer
1254 # @param File The file object for report
1256 def GenerateReport(self
, File
):
1257 FileWrite(File
, gSectionStart
)
1258 FileWrite(File
, "Firmware Device (FD)")
1259 FileWrite(File
, "FD Name: %s" % self
.FdName
)
1260 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
1261 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
1262 if len(self
.FdRegionList
) > 0:
1263 FileWrite(File
, gSectionSep
)
1264 for FdRegionItem
in self
.FdRegionList
:
1265 FdRegionItem
.GenerateReport(File
)
1267 FileWrite(File
, gSectionEnd
)
1272 # Reports platform information
1274 # This class reports the whole platform information
1276 class PlatformReport(object):
1278 # Constructor function for class PlatformReport
1280 # This constructor function generates PlatformReport object a platform build.
1281 # It generates report for platform summary, flash, global PCDs and detailed
1282 # module information for modules involved in platform build.
1284 # @param self The object pointer
1285 # @param Wa Workspace context information
1286 # @param MaList The list of modules in the platform build
1288 def __init__(self
, Wa
, MaList
, ReportType
):
1289 self
._WorkspaceDir
= Wa
.WorkspaceDir
1290 self
.PlatformName
= Wa
.Name
1291 self
.PlatformDscPath
= Wa
.Platform
1292 self
.Architectures
= " ".join(Wa
.ArchList
)
1293 self
.ToolChain
= Wa
.ToolChain
1294 self
.Target
= Wa
.BuildTarget
1295 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
1296 self
.BuildEnvironment
= platform
.platform()
1298 self
.PcdReport
= None
1299 if "PCD" in ReportType
:
1300 self
.PcdReport
= PcdReport(Wa
)
1302 self
.FdReportList
= []
1303 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
== None:
1304 for Fd
in Wa
.FdfProfile
.FdDict
:
1305 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
1307 self
.PredictionReport
= None
1308 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
1309 self
.PredictionReport
= PredictionReport(Wa
)
1311 self
.ModuleReportList
= []
1314 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
1316 for Pa
in Wa
.AutoGenObjectList
:
1317 for ModuleKey
in Pa
.Platform
.Modules
:
1318 self
.ModuleReportList
.append(ModuleReport(Pa
.Platform
.Modules
[ModuleKey
].M
, ReportType
))
1323 # Generate report for the whole platform.
1325 # This function generates report for platform information.
1326 # It comprises of platform summary, global PCD, flash and
1327 # module list sections.
1329 # @param self The object pointer
1330 # @param File The file object for report
1331 # @param BuildDuration The total time to build the modules
1332 # @param ReportType The kind of report items in the final report file
1334 def GenerateReport(self
, File
, BuildDuration
, ReportType
):
1335 FileWrite(File
, "Platform Summary")
1336 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
1337 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
1338 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
1339 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
1340 FileWrite(File
, "Target: %s" % self
.Target
)
1341 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
1342 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
1343 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
1344 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
1346 if "PCD" in ReportType
:
1347 self
.PcdReport
.GenerateReport(File
, None)
1349 if "FLASH" in ReportType
:
1350 for FdReportListItem
in self
.FdReportList
:
1351 FdReportListItem
.GenerateReport(File
)
1353 for ModuleReportItem
in self
.ModuleReportList
:
1354 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, ReportType
)
1356 if "EXECUTION_ORDER" in ReportType
:
1357 self
.PredictionReport
.GenerateReport(File
, None)
1359 ## BuildReport class
1361 # This base class contain the routines to collect data and then
1362 # applies certain format to the output report
1364 class BuildReport(object):
1366 # Constructor function for class BuildReport
1368 # This constructor function generates BuildReport object a platform build.
1369 # It generates report for platform summary, flash, global PCDs and detailed
1370 # module information for modules involved in platform build.
1372 # @param self The object pointer
1373 # @param ReportFile The file name to save report file
1374 # @param ReportType The kind of report items in the final report file
1376 def __init__(self
, ReportFile
, ReportType
):
1377 self
.ReportFile
= ReportFile
1379 self
.ReportList
= []
1380 self
.ReportType
= []
1382 for ReportTypeItem
in ReportType
:
1383 if ReportTypeItem
not in self
.ReportType
:
1384 self
.ReportType
.append(ReportTypeItem
)
1386 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "FLASH", "FIXED_ADDRESS"]
1388 # Adds platform report to the list
1390 # This function adds a platform report to the final report list.
1392 # @param self The object pointer
1393 # @param Wa Workspace context information
1394 # @param MaList The list of modules in the platform build
1396 def AddPlatformReport(self
, Wa
, MaList
=None):
1398 self
.ReportList
.append((Wa
, MaList
))
1401 # Generates the final report.
1403 # This function generates platform build report. It invokes GenerateReport()
1404 # method for every platform report in the list.
1406 # @param self The object pointer
1407 # @param BuildDuration The total time to build the modules
1409 def GenerateReport(self
, BuildDuration
):
1412 File
= open(self
.ReportFile
, "w+")
1414 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=self
.ReportFile
)
1416 for (Wa
, MaList
) in self
.ReportList
:
1417 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, self
.ReportType
)
1418 EdkLogger
.quiet("Report successfully saved to %s" % os
.path
.abspath(self
.ReportFile
))
1420 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
1422 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
1423 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1426 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1427 if __name__
== '__main__':