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 Pa
in Wa
.AutoGenObjectList
:
188 for Package
in Pa
.PackageList
:
189 for Protocol
in Package
.Protocols
:
190 GuidValue
= GuidStructureStringToGuidString(Package
.Protocols
[Protocol
])
191 self
._GuidDb
[GuidValue
.upper()] = Protocol
192 for Ppi
in Package
.Ppis
:
193 GuidValue
= GuidStructureStringToGuidString(Package
.Ppis
[Ppi
])
194 self
._GuidDb
[GuidValue
.upper()] = Ppi
195 for Guid
in Package
.Guids
:
196 GuidValue
= GuidStructureStringToGuidString(Package
.Guids
[Guid
])
197 self
._GuidDb
[GuidValue
.upper()] = Guid
200 # Parse the binary dependency expression files.
202 # This function parses the binary dependency expression file and translate it
203 # to the instruction list.
205 # @param self The object pointer
206 # @param DepexFileName The file name of binary dependency expression file.
208 def ParseDepexFile(self
, DepexFileName
):
209 DepexFile
= open(DepexFileName
, "rb")
211 OpCode
= DepexFile
.read(1)
213 Statement
= gOpCodeList
[struct
.unpack("B", OpCode
)[0]]
214 if Statement
in ["BEFORE", "AFTER", "PUSH"]:
215 GuidValue
= "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
216 struct
.unpack("LHHBBBBBBBB", DepexFile
.read(16))
217 GuidString
= self
._GuidDb
.get(GuidValue
, GuidValue
)
218 Statement
= "%s %s" % (Statement
, GuidString
)
219 DepexStatement
.append(Statement
)
220 OpCode
= DepexFile
.read(1)
222 return DepexStatement
225 # Reports library information
227 # This class reports the module library subsection in the build report file.
229 class LibraryReport(object):
231 # Constructor function for class LibraryReport
233 # This constructor function generates LibraryReport object for
236 # @param self The object pointer
237 # @param M Module context information
239 def __init__(self
, M
):
240 self
.LibraryList
= []
241 if int(str(M
.AutoGenVersion
), 0) >= 0x00010005:
242 self
._EdkIIModule
= True
244 self
._EdkIIModule
= False
246 for Lib
in M
.DependentLibraryList
:
247 LibInfPath
= str(Lib
)
248 LibClassList
= Lib
.LibraryClass
[0].LibraryClass
249 LibConstructorList
= Lib
.ConstructorList
250 LibDesstructorList
= Lib
.DestructorList
251 LibDepexList
= Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]
252 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
))
255 # Generate report for module library information
257 # This function generates report for the module library.
258 # If the module is EDKII style one, the additional library class, library
259 # constructor/destructor and dependency expression may also be reported.
261 # @param self The object pointer
262 # @param File The file object for report
264 def GenerateReport(self
, File
):
265 FileWrite(File
, gSubSectionStart
)
266 FileWrite(File
, "Library")
267 if len(self
.LibraryList
) > 0:
268 FileWrite(File
, gSubSectionSep
)
269 for LibraryItem
in self
.LibraryList
:
270 LibInfPath
= LibraryItem
[0]
271 FileWrite(File
, LibInfPath
)
274 # Report library class, library constructor and destructor for
275 # EDKII style module.
277 if self
._EdkIIModule
:
278 LibClass
= LibraryItem
[1]
280 LibConstructor
= " ".join(LibraryItem
[2])
282 EdkIILibInfo
+= " C = " + LibConstructor
283 LibDestructor
= " ".join(LibraryItem
[3])
285 EdkIILibInfo
+= " D = " + LibDestructor
286 LibDepex
= " ".join(LibraryItem
[4])
288 EdkIILibInfo
+= " Depex = " + LibDepex
290 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
292 FileWrite(File
, "{%s}" % LibClass
)
294 FileWrite(File
, gSubSectionEnd
)
297 # Reports dependency expression information
299 # This class reports the module dependency expression subsection in the build report file.
301 class DepexReport(object):
303 # Constructor function for class DepexReport
305 # This constructor function generates DepexReport object for
306 # a module. If the module source contains the DXS file (usually EDK
307 # style module), it uses the dependency in DXS file; otherwise,
308 # it uses the dependency expression from its own INF [Depex] section
309 # and then merges with the ones from its dependent library INF.
311 # @param self The object pointer
312 # @param M Module context information
314 def __init__(self
, M
):
316 self
._DepexFileName
= os
.path
.join(M
.BuildDir
, "OUTPUT", M
.Module
.BaseName
+ ".depex")
317 ModuleType
= M
.ModuleType
319 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
321 if ModuleType
in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "UEFI_APPLICATION"]:
324 for Source
in M
.SourceFileList
:
325 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
326 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
328 self
.Depex
= Match
.group(1).strip()
332 self
.Depex
= M
.DepexExpressionList
.get(M
.ModuleType
, "")
333 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
334 if not self
.ModuleDepex
:
335 self
.ModuleDepex
= "(None)"
338 for Lib
in M
.DependentLibraryList
:
339 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
341 LibDepexList
.append("(" + LibDepex
+ ")")
342 self
.LibraryDepex
= " AND ".join(LibDepexList
)
343 if not self
.LibraryDepex
:
344 self
.LibraryDepex
= "(None)"
348 # Generate report for module dependency expression information
350 # This function generates report for the module dependency expression.
352 # @param self The object pointer
353 # @param File The file object for report
354 # @param GlobalDepexParser The platform global Dependency expression parser object
356 def GenerateReport(self
, File
, GlobalDepexParser
):
360 FileWrite(File
, gSubSectionStart
)
361 if os
.path
.isfile(self
._DepexFileName
):
363 DepexStatements
= GlobalDepexParser
.ParseDepexFile(self
._DepexFileName
)
364 FileWrite(File
, "Final Dependency Expression (DEPEX) Instructions")
365 for DepexStatement
in DepexStatements
:
366 FileWrite(File
, " %s" % DepexStatement
)
367 FileWrite(File
, gSubSectionSep
)
369 EdkLogger
.warn(None, "Dependency expression file is corrupted", self
._DepexFileName
)
371 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
373 if self
.Source
== "INF":
374 FileWrite(File
, "%s" % self
.Depex
, True)
375 FileWrite(File
, gSubSectionSep
)
376 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
377 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
379 FileWrite(File
, "%s" % self
.Depex
)
380 FileWrite(File
, gSubSectionEnd
)
383 # Reports dependency expression information
385 # This class reports the module build flags subsection in the build report file.
387 class BuildFlagsReport(object):
389 # Constructor function for class BuildFlagsReport
391 # This constructor function generates BuildFlagsReport object for
392 # a module. It reports the build tool chain tag and all relevant
393 # build flags to build the module.
395 # @param self The object pointer
396 # @param M Module context information
398 def __init__(self
, M
):
401 # Add build flags according to source file extension so that
402 # irrelevant ones can be filtered out.
404 for Source
in M
.SourceFileList
:
405 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
406 if Ext
in [".c", ".cc", ".cpp"]:
407 BuildOptions
["CC"] = 1
408 elif Ext
in [".s", ".asm"]:
409 BuildOptions
["PP"] = 1
410 BuildOptions
["ASM"] = 1
411 elif Ext
in [".vfr"]:
412 BuildOptions
["VFRPP"] = 1
413 BuildOptions
["VFR"] = 1
414 elif Ext
in [".dxs"]:
415 BuildOptions
["APP"] = 1
416 BuildOptions
["CC"] = 1
417 elif Ext
in [".asl"]:
418 BuildOptions
["ASLPP"] = 1
419 BuildOptions
["ASL"] = 1
420 elif Ext
in [".aslc"]:
421 BuildOptions
["ASLCC"] = 1
422 BuildOptions
["ASLDLINK"] = 1
423 BuildOptions
["CC"] = 1
424 elif Ext
in [".asm16"]:
425 BuildOptions
["ASMLINK"] = 1
426 BuildOptions
["SLINK"] = 1
427 BuildOptions
["DLINK"] = 1
430 # Save module build flags.
432 self
.ToolChainTag
= M
.ToolChain
434 for Tool
in BuildOptions
:
435 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
438 # Generate report for module build flags information
440 # This function generates report for the module build flags expression.
442 # @param self The object pointer
443 # @param File The file object for report
445 def GenerateReport(self
, File
):
446 FileWrite(File
, gSubSectionStart
)
447 FileWrite(File
, "Build Flags")
448 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
449 for Tool
in self
.BuildFlags
:
450 FileWrite(File
, gSubSectionSep
)
451 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
453 FileWrite(File
, gSubSectionEnd
)
457 # Reports individual module information
459 # This class reports the module section in the build report file.
460 # It comprises of module summary, module PCD, library, dependency expression,
461 # build flags sections.
463 class ModuleReport(object):
465 # Constructor function for class ModuleReport
467 # This constructor function generates ModuleReport object for
468 # a separate module in a platform build.
470 # @param self The object pointer
471 # @param M Module context information
472 # @param ReportType The kind of report items in the final report file
474 def __init__(self
, M
, ReportType
):
475 self
.ModuleName
= M
.Module
.BaseName
476 self
.ModuleInfPath
= M
.MetaFile
.File
477 self
.FileGuid
= M
.Guid
479 self
.BuildTimeStamp
= None
482 ModuleType
= M
.ModuleType
484 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
486 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
488 if ModuleType
== "DXE_SMM_DRIVER":
489 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
490 if int(PiSpec
, 0) >= 0x0001000A:
491 ModuleType
= "SMM_DRIVER"
492 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
493 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
494 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
495 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
496 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
497 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
499 self
._BuildDir
= M
.BuildDir
500 self
.ModulePcdSet
= {}
501 if "PCD" in ReportType
:
503 # Collect all module used PCD set: module INF referenced directly or indirectly.
504 # It also saves module INF default values of them in case they exist.
506 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
507 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
509 self
.LibraryReport
= None
510 if "LIBRARY" in ReportType
:
511 self
.LibraryReport
= LibraryReport(M
)
513 self
.DepexReport
= None
514 if "DEPEX" in ReportType
:
515 self
.DepexReport
= DepexReport(M
)
517 if "BUILD_FLAGS" in ReportType
:
518 self
.BuildFlagsReport
= BuildFlagsReport(M
)
522 # Generate report for module information
524 # This function generates report for separate module expression
525 # in a platform build.
527 # @param self The object pointer
528 # @param File The file object for report
529 # @param GlobalPcdReport The platform global PCD report object
530 # @param GlobalPredictionReport The platform global Prediction report object
531 # @param GlobalDepexParser The platform global Dependency expression parser object
532 # @param ReportType The kind of report items in the final report file
534 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, GlobalDepexParser
, ReportType
):
535 FileWrite(File
, gSectionStart
)
537 FwReportFileName
= os
.path
.join(self
._BuildDir
, "DEBUG", self
.ModuleName
+ ".txt")
538 if os
.path
.isfile(FwReportFileName
):
540 FileContents
= open(FwReportFileName
).read()
541 Match
= gModuleSizePattern
.search(FileContents
)
543 self
.Size
= int(Match
.group(1))
545 Match
= gTimeStampPattern
.search(FileContents
)
547 self
.BuildTimeStamp
= datetime
.fromtimestamp(int(Match
.group(1)))
549 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
551 FileWrite(File
, "Module Summary")
552 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
553 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
554 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
556 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
557 if self
.BuildTimeStamp
:
558 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
560 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
561 if self
.UefiSpecVersion
:
562 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
563 if self
.PiSpecVersion
:
564 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
566 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
568 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
569 if self
.PciClassCode
:
570 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
572 FileWrite(File
, gSectionSep
)
574 if "PCD" in ReportType
:
575 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
577 if "LIBRARY" in ReportType
:
578 self
.LibraryReport
.GenerateReport(File
)
580 if "DEPEX" in ReportType
:
581 self
.DepexReport
.GenerateReport(File
, GlobalDepexParser
)
583 if "BUILD_FLAGS" in ReportType
:
584 self
.BuildFlagsReport
.GenerateReport(File
)
586 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
587 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
589 FileWrite(File
, gSectionEnd
)
592 # Reports platform and module PCD information
594 # This class reports the platform PCD section and module PCD subsection
595 # in the build report file.
597 class PcdReport(object):
599 # Constructor function for class PcdReport
601 # This constructor function generates PcdReport object a platform build.
602 # It collects the whole PCD database from platform DSC files, platform
603 # flash description file and package DEC files.
605 # @param self The object pointer
606 # @param Wa Workspace context information
608 def __init__(self
, Wa
):
612 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
616 self
.ModulePcdOverride
= {}
617 for Pa
in Wa
.AutoGenObjectList
:
619 # Collect all platform referenced PCDs and grouped them by PCD token space
622 for Pcd
in Pa
.AllPcdList
:
623 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
624 if Pcd
not in PcdList
:
626 if len(Pcd
.TokenCName
) > self
.MaxLen
:
627 self
.MaxLen
= len(Pcd
.TokenCName
)
629 for Module
in Pa
.Platform
.Modules
.values():
631 # Collect module override PCDs
633 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
634 TokenCName
= ModulePcd
.TokenCName
635 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
636 ModuleDefault
= ModulePcd
.DefaultValue
637 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
638 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
642 # Collect PCD DEC default value.
644 self
.DecPcdDefault
= {}
645 for Pa
in Wa
.AutoGenObjectList
:
646 for Package
in Pa
.PackageList
:
647 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
648 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
649 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
651 # Collect PCDs defined in DSC common section
653 self
.DscPcdDefault
= {}
654 for Platform
in Wa
.BuildDatabase
.WorkspaceDb
.PlatformList
:
655 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
656 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
658 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
661 # Generate report for PCD information
663 # This function generates report for separate module expression
664 # in a platform build.
666 # @param self The object pointer
667 # @param File The file object for report
668 # @param ModulePcdSet Set of all PCDs referenced by module or None for
669 # platform PCD report
670 # @param DscOverridePcds Module DSC override PCDs set
672 def GenerateReport(self
, File
, ModulePcdSet
):
673 if ModulePcdSet
== None:
675 # For platform global PCD section
677 FileWrite(File
, gSectionStart
)
678 FileWrite(File
, "Platform Configuration Database Report")
679 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
680 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
681 FileWrite(File
, " *M - Module scoped PCD override")
682 FileWrite(File
, gSectionSep
)
685 # For module PCD sub-section
687 FileWrite(File
, gSubSectionStart
)
688 FileWrite(File
, "PCD")
689 FileWrite(File
, gSubSectionSep
)
691 for Key
in self
.AllPcds
:
693 # Group PCD by their token space GUID C Name
696 for Type
in self
.AllPcds
[Key
]:
698 # Group PCD by their usage type
700 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
701 for Pcd
in self
.AllPcds
[Key
][Type
]:
703 # Get PCD default value and their override relationship
705 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
706 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
707 DscDefaultValue
= self
.FdfPcdSet
.get((Pcd
.TokenCName
, Key
), DscDefaultValue
)
708 InfDefaultValue
= None
710 PcdValue
= DecDefaultValue
712 PcdValue
= DscDefaultValue
713 if ModulePcdSet
!= None:
714 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
716 InfDefault
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
720 if ModulePcdSet
== None:
726 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
727 PcdValueNumber
= int(PcdValue
.strip(), 0)
728 if DecDefaultValue
== None:
731 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
732 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
734 if InfDefaultValue
== None:
737 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
738 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
740 if DscDefaultValue
== None:
743 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
744 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
746 if DecDefaultValue
== None:
749 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
751 if InfDefaultValue
== None:
754 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
756 if DscDefaultValue
== None:
759 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
762 # Report PCD item according to their override relationship
764 if DecMatch
and InfMatch
:
765 FileWrite(File
, ' %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
768 if (Pcd
.TokenCName
, Key
) in self
.FdfPcdSet
:
769 FileWrite(File
, ' *F %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
771 FileWrite(File
, ' *P %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
773 FileWrite(File
, ' *M %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
775 if TypeName
in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):
776 for SkuInfo
in Pcd
.SkuInfoList
.values():
777 if TypeName
in ('DYNHII', 'DEXHII'):
778 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
780 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
782 if not DscMatch
and DscDefaultValue
!= None:
783 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', DscDefaultValue
.strip()))
785 if not InfMatch
and InfDefaultValue
!= None:
786 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', InfDefaultValue
.strip()))
788 if not DecMatch
and DecDefaultValue
!= None:
789 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', DecDefaultValue
.strip()))
791 if ModulePcdSet
== None:
792 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
793 for ModulePath
in ModuleOverride
:
794 ModuleDefault
= ModuleOverride
[ModulePath
]
795 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
796 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
797 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
799 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
802 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 19, ModulePath
, ModuleDefault
.strip()))
804 if ModulePcdSet
== None:
805 FileWrite(File
, gSectionEnd
)
807 FileWrite(File
, gSubSectionEnd
)
812 # Reports platform and module Prediction information
814 # This class reports the platform execution order prediction section and
815 # module load fixed address prediction subsection in the build report file.
817 class PredictionReport(object):
819 # Constructor function for class PredictionReport
821 # This constructor function generates PredictionReport object for the platform.
823 # @param self: The object pointer
824 # @param Wa Workspace context information
826 def __init__(self
, Wa
):
827 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
828 self
._MapFileParsed
= False
829 self
._EotToolInvoked
= False
830 self
._FvDir
= Wa
.FvDir
831 self
._EotDir
= Wa
.BuildDir
832 self
._FfsEntryPoint
= {}
834 self
._SourceList
= []
835 self
.FixedMapDict
= {}
840 # Collect all platform reference source files and GUID C Name
842 for Pa
in Wa
.AutoGenObjectList
:
843 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
845 # BASE typed modules are EFI agnostic, so we need not scan
846 # their source code to find PPI/Protocol produce or consume
849 if Module
.ModuleType
== "BASE":
852 # Add module referenced source files
854 self
._SourceList
.append(str(Module
))
856 for Source
in Module
.SourceFileList
:
857 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
858 self
._SourceList
.append(" " + str(Source
))
859 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
860 for IncludeFile
in IncludeList
.values():
861 self
._SourceList
.append(" " + IncludeFile
)
863 for Guid
in Module
.PpiList
:
864 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
865 for Guid
in Module
.ProtocolList
:
866 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
867 for Guid
in Module
.GuidList
:
868 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
870 if Module
.Guid
and not Module
.IsLibrary
:
871 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
872 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
873 RealEntryPoint
= "_ModuleEntryPoint"
875 RealEntryPoint
= EntryPoint
876 if EntryPoint
== "_ModuleEntryPoint":
877 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
878 Match
= gGlueLibEntryPoint
.search(CCFlags
)
880 EntryPoint
= Match
.group(1)
882 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
886 # Collect platform firmware volume list as the input of EOT.
890 for Fd
in Wa
.FdfProfile
.FdDict
:
891 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
892 if FdRegion
.RegionType
!= "FV":
894 for FvName
in FdRegion
.RegionDataList
:
895 if FvName
in self
._FvList
:
897 self
._FvList
.append(FvName
)
898 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
899 for Section
in Ffs
.SectionList
:
901 for FvSection
in Section
.SectionList
:
902 if FvSection
.FvName
in self
._FvList
:
904 self
._FvList
.append(FvSection
.FvName
)
905 except AttributeError:
910 # Parse platform fixed address map files
912 # This function parses the platform final fixed address map file to get
913 # the database of predicted fixed address for module image base, entry point
916 # @param self: The object pointer
918 def _ParseMapFile(self
):
919 if self
._MapFileParsed
:
921 self
._MapFileParsed
= True
922 if os
.path
.isfile(self
._MapFileName
):
924 FileContents
= open(self
._MapFileName
).read()
925 for Match
in gMapFileItemPattern
.finditer(FileContents
):
926 AddressType
= Match
.group(1)
927 BaseAddress
= Match
.group(2)
928 EntryPoint
= Match
.group(3)
929 Guid
= Match
.group(4).upper()
930 List
= self
.FixedMapDict
.setdefault(Guid
, [])
931 List
.append((AddressType
, BaseAddress
, "*I"))
932 List
.append((AddressType
, EntryPoint
, "*E"))
934 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
937 # Invokes EOT tool to get the predicted the execution order.
939 # This function invokes EOT tool to calculate the predicted dispatch order
941 # @param self: The object pointer
943 def _InvokeEotTool(self
):
944 if self
._EotToolInvoked
:
947 self
._EotToolInvoked
= True
949 for FvName
in self
._FvList
:
950 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
951 if os
.path
.isfile(FvFile
):
952 FvFileList
.append(FvFile
)
954 if len(FvFileList
) == 0:
957 # Write source file list and GUID file list to an intermediate file
958 # as the input for EOT tool and dispatch List as the output file
961 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
962 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
963 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
965 TempFile
= open(SourceList
, "w+")
966 for Item
in self
._SourceList
:
967 FileWrite(TempFile
, Item
)
969 TempFile
= open(GuidList
, "w+")
970 for Key
in self
._GuidMap
:
971 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
975 from Eot
.Eot
import Eot
978 # Invoke EOT tool and echo its runtime performance
980 EotStartTime
= time
.time()
981 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
982 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
983 EotEndTime
= time
.time()
984 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
985 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
988 # Parse the output of EOT tool
990 for Line
in open(DispatchList
):
991 if len(Line
.split()) < 4:
993 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
994 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
995 if len(Symbol
) > self
.MaxLen
:
996 self
.MaxLen
= len(Symbol
)
997 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
999 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1000 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1004 # Generate platform execution order report
1006 # This function generates the predicted module execution order.
1008 # @param self The object pointer
1009 # @param File The file object for report
1011 def _GenerateExecutionOrderReport(self
, File
):
1012 self
._InvokeEotTool
()
1013 if len(self
.ItemList
) == 0:
1015 FileWrite(File
, gSectionStart
)
1016 FileWrite(File
, "Execution Order Prediction")
1017 FileWrite(File
, "*P PEI phase")
1018 FileWrite(File
, "*D DXE phase")
1019 FileWrite(File
, "*E Module INF entry point name")
1020 FileWrite(File
, "*N Module notification function name")
1022 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1023 FileWrite(File
, gSectionSep
)
1024 for Item
in self
.ItemList
:
1025 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1027 FileWrite(File
, gSectionStart
)
1030 # Generate Fixed Address report.
1032 # This function generate the predicted fixed address report for a module
1033 # specified by Guid.
1035 # @param self The object pointer
1036 # @param File The file object for report
1037 # @param Guid The module Guid value.
1038 # @param NotifyList The list of all notify function in a module
1040 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1041 self
._ParseMapFile
()
1042 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1043 if not FixedAddressList
:
1046 FileWrite(File
, gSubSectionStart
)
1047 FileWrite(File
, "Fixed Address Prediction")
1048 FileWrite(File
, "*I Image Loading Address")
1049 FileWrite(File
, "*E Entry Point Address")
1050 FileWrite(File
, "*N Notification Function Address")
1051 FileWrite(File
, "*F Flash Address")
1052 FileWrite(File
, "*M Memory Address")
1053 FileWrite(File
, "*S SMM RAM Offset")
1054 FileWrite(File
, "TOM Top of Memory")
1056 FileWrite(File
, "Type Address Name")
1057 FileWrite(File
, gSubSectionSep
)
1058 for Item
in FixedAddressList
:
1063 Name
= "(Image Base)"
1064 elif Symbol
== "*E":
1065 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1066 elif Symbol
in NotifyList
:
1074 elif "Memory" in Type
:
1080 Value
= "TOM" + Value
1082 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1085 # Generate report for the prediction part
1087 # This function generate the predicted fixed address report for a module or
1088 # predicted module execution order for a platform.
1089 # If the input Guid is None, then, it generates the predicted module execution order;
1090 # otherwise it generated the module fixed loading address for the module specified by
1093 # @param self The object pointer
1094 # @param File The file object for report
1095 # @param Guid The module Guid value.
1097 def GenerateReport(self
, File
, Guid
):
1099 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1101 self
._GenerateExecutionOrderReport
(File
)
1104 # Reports FD region information
1106 # This class reports the FD subsection in the build report file.
1107 # It collects region information of platform flash device.
1108 # If the region is a firmware volume, it lists the set of modules
1109 # and its space information; otherwise, it only lists its region name,
1110 # base address and size in its sub-section header.
1111 # If there are nesting FVs, the nested FVs will list immediate after
1112 # this FD region subsection
1114 class FdRegionReport(object):
1116 # Discover all the nested FV name list.
1118 # This is an internal worker function to discover the all the nested FV information
1119 # in the parent firmware volume. It uses deep first search algorithm recursively to
1120 # find all the FV list name and append them to the list.
1122 # @param self The object pointer
1123 # @param FvName The name of current firmware file system
1124 # @param Wa Workspace context information
1126 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1127 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1128 for Section
in Ffs
.SectionList
:
1130 for FvSection
in Section
.SectionList
:
1131 if FvSection
.FvName
in self
.FvList
:
1133 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1134 self
.FvList
.append(FvSection
.FvName
)
1135 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1136 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1137 except AttributeError:
1141 # Constructor function for class FdRegionReport
1143 # This constructor function generates FdRegionReport object for a specified FdRegion.
1144 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1145 # volume list. This function also collects GUID map in order to dump module identification
1146 # in the final report.
1148 # @param self: The object pointer
1149 # @param FdRegion The current FdRegion object
1150 # @param Wa Workspace context information
1152 def __init__(self
, FdRegion
, Wa
):
1153 self
.Type
= FdRegion
.RegionType
1154 self
.BaseAddress
= FdRegion
.Offset
1155 self
.Size
= FdRegion
.Size
1159 self
._FvDir
= Wa
.FvDir
1162 # If the input FdRegion is not a firmware volume,
1165 if self
.Type
!= "FV":
1169 # Find all nested FVs in the FdRegion
1171 for FvName
in FdRegion
.RegionDataList
:
1172 if FvName
in self
.FvList
:
1174 self
.FvList
.append(FvName
)
1175 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1176 self
._DiscoverNestedFvList
(FvName
, Wa
)
1180 # Collect PCDs declared in DEC files.
1182 for Pa
in Wa
.AutoGenObjectList
:
1183 for Package
in Pa
.PackageList
:
1184 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1185 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1186 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1188 # Collect PCDs defined in DSC common section
1190 for Platform
in Wa
.BuildDatabase
.WorkspaceDb
.PlatformList
:
1191 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
1192 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1193 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1196 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1198 self
._GuidsDb
["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
1199 self
._GuidsDb
["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"
1201 # Add ACPI table storage file
1203 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1205 for Pa
in Wa
.AutoGenObjectList
:
1206 for ModuleKey
in Pa
.Platform
.Modules
:
1207 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1208 InfPath
= os
.path
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1209 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1212 # Collect the GUID map in the FV firmware volume
1214 for FvName
in self
.FvList
:
1215 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1218 # collect GUID map for binary EFI file in FDF file.
1220 Guid
= Ffs
.NameGuid
.upper()
1221 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1223 PcdTokenspace
= Match
.group(1)
1224 PcdToken
= Match
.group(2)
1225 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1226 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1227 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1228 for Section
in Ffs
.SectionList
:
1230 ModuleSectFile
= os
.path
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1231 self
._GuidsDb
[Guid
] = ModuleSectFile
1232 except AttributeError:
1234 except AttributeError:
1239 # Internal worker function to generate report for the FD region
1241 # This internal worker function to generate report for the FD region.
1242 # It the type is firmware volume, it lists offset and module identification.
1244 # @param self The object pointer
1245 # @param File The file object for report
1246 # @param Title The title for the FD subsection
1247 # @param BaseAddress The base address for the FD region
1248 # @param Size The size of the FD region
1249 # @param FvName The FV name if the FD region is a firmware volume
1251 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1252 FileWrite(File
, gSubSectionStart
)
1253 FileWrite(File
, Title
)
1254 FileWrite(File
, "Type: %s" % Type
)
1255 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1257 if self
.Type
== "FV":
1261 FvReportFileName
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv.txt")
1264 # Collect size info in the firmware volume.
1266 FvReport
= open(FvReportFileName
).read()
1267 Match
= gFvTotalSizePattern
.search(FvReport
)
1269 FvTotalSize
= int(Match
.group(1), 16)
1270 Match
= gFvTakenSizePattern
.search(FvReport
)
1272 FvTakenSize
= int(Match
.group(1), 16)
1273 FvFreeSize
= FvTotalSize
- FvTakenSize
1275 # Write size information to the report file.
1277 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1278 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1279 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1280 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1281 FileWrite(File
, "Offset Module")
1282 FileWrite(File
, gSubSectionSep
)
1284 # Write module offset and module identification to the report file.
1287 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1288 Guid
= Match
.group(2).upper()
1289 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1290 OffsetList
= OffsetInfo
.keys()
1292 for Offset
in OffsetList
:
1293 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1295 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1297 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1298 FileWrite(File
, gSubSectionEnd
)
1301 # Generate report for the FD region
1303 # This function generates report for the FD region.
1305 # @param self The object pointer
1306 # @param File The file object for report
1308 def GenerateReport(self
, File
):
1309 if (len(self
.FvList
) > 0):
1310 for FvItem
in self
.FvList
:
1311 Info
= self
.FvInfo
[FvItem
]
1312 self
._GenerateReport
(File
, Info
[0], "FV", Info
[1], Info
[2], FvItem
)
1314 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
1317 # Reports FD information
1319 # This class reports the FD section in the build report file.
1320 # It collects flash device information for a platform.
1322 class FdReport(object):
1324 # Constructor function for class FdReport
1326 # This constructor function generates FdReport object for a specified
1329 # @param self The object pointer
1330 # @param Fd The current Firmware device object
1331 # @param Wa Workspace context information
1333 def __init__(self
, Fd
, Wa
):
1334 self
.FdName
= Fd
.FdUiName
1335 self
.BaseAddress
= Fd
.BaseAddress
1337 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
1340 # Generate report for the firmware device.
1342 # This function generates report for the firmware device.
1344 # @param self The object pointer
1345 # @param File The file object for report
1347 def GenerateReport(self
, File
):
1348 FileWrite(File
, gSectionStart
)
1349 FileWrite(File
, "Firmware Device (FD)")
1350 FileWrite(File
, "FD Name: %s" % self
.FdName
)
1351 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
1352 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
1353 if len(self
.FdRegionList
) > 0:
1354 FileWrite(File
, gSectionSep
)
1355 for FdRegionItem
in self
.FdRegionList
:
1356 FdRegionItem
.GenerateReport(File
)
1358 FileWrite(File
, gSectionEnd
)
1363 # Reports platform information
1365 # This class reports the whole platform information
1367 class PlatformReport(object):
1369 # Constructor function for class PlatformReport
1371 # This constructor function generates PlatformReport object a platform build.
1372 # It generates report for platform summary, flash, global PCDs and detailed
1373 # module information for modules involved in platform build.
1375 # @param self The object pointer
1376 # @param Wa Workspace context information
1377 # @param MaList The list of modules in the platform build
1379 def __init__(self
, Wa
, MaList
, ReportType
):
1380 self
._WorkspaceDir
= Wa
.WorkspaceDir
1381 self
.PlatformName
= Wa
.Name
1382 self
.PlatformDscPath
= Wa
.Platform
1383 self
.Architectures
= " ".join(Wa
.ArchList
)
1384 self
.ToolChain
= Wa
.ToolChain
1385 self
.Target
= Wa
.BuildTarget
1386 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
1387 self
.BuildEnvironment
= platform
.platform()
1389 self
.PcdReport
= None
1390 if "PCD" in ReportType
:
1391 self
.PcdReport
= PcdReport(Wa
)
1393 self
.FdReportList
= []
1394 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
== None:
1395 for Fd
in Wa
.FdfProfile
.FdDict
:
1396 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
1398 self
.PredictionReport
= None
1399 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
1400 self
.PredictionReport
= PredictionReport(Wa
)
1402 self
.DepexParser
= None
1403 if "DEPEX" in ReportType
:
1404 self
.DepexParser
= DepexParser(Wa
)
1406 self
.ModuleReportList
= []
1408 self
._IsModuleBuild
= True
1410 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
1412 self
._IsModuleBuild
= False
1413 for Pa
in Wa
.AutoGenObjectList
:
1414 for ModuleKey
in Pa
.Platform
.Modules
:
1415 self
.ModuleReportList
.append(ModuleReport(Pa
.Platform
.Modules
[ModuleKey
].M
, ReportType
))
1420 # Generate report for the whole platform.
1422 # This function generates report for platform information.
1423 # It comprises of platform summary, global PCD, flash and
1424 # module list sections.
1426 # @param self The object pointer
1427 # @param File The file object for report
1428 # @param BuildDuration The total time to build the modules
1429 # @param ReportType The kind of report items in the final report file
1431 def GenerateReport(self
, File
, BuildDuration
, ReportType
):
1432 FileWrite(File
, "Platform Summary")
1433 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
1434 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
1435 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
1436 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
1437 FileWrite(File
, "Target: %s" % self
.Target
)
1438 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
1439 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
1440 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
1441 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
1443 if not self
._IsModuleBuild
:
1444 if "PCD" in ReportType
:
1445 self
.PcdReport
.GenerateReport(File
, None)
1447 if "FLASH" in ReportType
:
1448 for FdReportListItem
in self
.FdReportList
:
1449 FdReportListItem
.GenerateReport(File
)
1451 for ModuleReportItem
in self
.ModuleReportList
:
1452 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
1454 if not self
._IsModuleBuild
:
1455 if "EXECUTION_ORDER" in ReportType
:
1456 self
.PredictionReport
.GenerateReport(File
, None)
1458 ## BuildReport class
1460 # This base class contain the routines to collect data and then
1461 # applies certain format to the output report
1463 class BuildReport(object):
1465 # Constructor function for class BuildReport
1467 # This constructor function generates BuildReport object a platform build.
1468 # It generates report for platform summary, flash, global PCDs and detailed
1469 # module information for modules involved in platform build.
1471 # @param self The object pointer
1472 # @param ReportFile The file name to save report file
1473 # @param ReportType The kind of report items in the final report file
1475 def __init__(self
, ReportFile
, ReportType
):
1476 self
.ReportFile
= ReportFile
1478 self
.ReportList
= []
1479 self
.ReportType
= []
1481 for ReportTypeItem
in ReportType
:
1482 if ReportTypeItem
not in self
.ReportType
:
1483 self
.ReportType
.append(ReportTypeItem
)
1485 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "FLASH", "FIXED_ADDRESS"]
1487 # Adds platform report to the list
1489 # This function adds a platform report to the final report list.
1491 # @param self The object pointer
1492 # @param Wa Workspace context information
1493 # @param MaList The list of modules in the platform build
1495 def AddPlatformReport(self
, Wa
, MaList
=None):
1497 self
.ReportList
.append((Wa
, MaList
))
1500 # Generates the final report.
1502 # This function generates platform build report. It invokes GenerateReport()
1503 # method for every platform report in the list.
1505 # @param self The object pointer
1506 # @param BuildDuration The total time to build the modules
1508 def GenerateReport(self
, BuildDuration
):
1512 for (Wa
, MaList
) in self
.ReportList
:
1513 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, self
.ReportType
)
1514 SaveFileOnChange(self
.ReportFile
, File
.getvalue(), False)
1515 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
1517 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
1519 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
1520 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1523 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1524 if __name__
== '__main__':