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
36 from Common
.DataType
import TAB_LINE_BREAK
37 from Common
.DataType
import TAB_DEPEX
38 from Common
.DataType
import TAB_SLASH
39 from Common
.DataType
import TAB_SPACE_SPLIT
40 from Common
.DataType
import TAB_BRG_PCD
41 from Common
.DataType
import TAB_BRG_LIBRARY
42 from Common
.DataType
import TAB_BACK_SLASH
44 ## Pattern to extract contents in EDK DXS files
45 gDxsDependencyPattern
= re
.compile(r
"DEPENDENCY_START(.+)DEPENDENCY_END", re
.DOTALL
)
47 ## Pattern to find total FV total size, occupied size in flash report intermediate file
48 gFvTotalSizePattern
= re
.compile(r
"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
49 gFvTakenSizePattern
= re
.compile(r
"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
51 ## Pattern to find module size and time stamp in module summary report intermediate file
52 gModuleSizePattern
= re
.compile(r
"MODULE_SIZE = (\d+)")
53 gTimeStampPattern
= re
.compile(r
"TIME_STAMP = (\d+)")
55 ## Pattern to find GUID value in flash description files
56 gPcdGuidPattern
= re
.compile(r
"PCD\((\w+)[.](\w+)\)")
58 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
59 gOffsetGuidPattern
= re
.compile(r
"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
61 ## Pattern to find module base address and entry point in fixed flash map file
62 gModulePattern
= r
"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
63 gMapFileItemPattern
= re
.compile(gModulePattern
% {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
65 ## Pattern to find all module referenced header files in source files
66 gIncludePattern
= re
.compile(r
'#include\s*["<]([^">]+)[">]')
67 gIncludePattern2
= re
.compile(r
"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
69 ## Pattern to find the entry point for EDK module using EDKII Glue library
70 gGlueLibEntryPoint
= re
.compile(r
"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
72 ## Tags for MaxLength of line in report
75 ## Tags for section start, end and separator
76 gSectionStart
= ">" + "=" * (gLineMaxLength
-2) + "<"
77 gSectionEnd
= "<" + "=" * (gLineMaxLength
-2) + ">" + "\n"
78 gSectionSep
= "=" * gLineMaxLength
80 ## Tags for subsection start, end and separator
81 gSubSectionStart
= ">" + "-" * (gLineMaxLength
-2) + "<"
82 gSubSectionEnd
= "<" + "-" * (gLineMaxLength
-2) + ">"
83 gSubSectionSep
= "-" * gLineMaxLength
86 ## The look up table to map PCD type to pair of report display type and DEC type
88 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),
89 'PatchableInModule': ('PATCH', 'PatchableInModule'),
90 'FeatureFlag' : ('FLAG', 'FeatureFlag'),
91 'Dynamic' : ('DYN', 'Dynamic'),
92 'DynamicHii' : ('DYNHII', 'Dynamic'),
93 'DynamicVpd' : ('DYNVPD', 'Dynamic'),
94 'DynamicEx' : ('DEX', 'Dynamic'),
95 'DynamicExHii' : ('DEXHII', 'Dynamic'),
96 'DynamicExVpd' : ('DEXVPD', 'Dynamic'),
99 ## The look up table to map module type to driver type
101 'SEC' : '0x3 (SECURITY_CORE)',
102 'PEI_CORE' : '0x4 (PEI_CORE)',
103 'PEIM' : '0x6 (PEIM)',
104 'DXE_CORE' : '0x5 (DXE_CORE)',
105 'DXE_DRIVER' : '0x7 (DRIVER)',
106 'DXE_SAL_DRIVER' : '0x7 (DRIVER)',
107 'DXE_SMM_DRIVER' : '0x7 (DRIVER)',
108 'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',
109 'UEFI_DRIVER' : '0x7 (DRIVER)',
110 'UEFI_APPLICATION' : '0x9 (APPLICATION)',
111 'SMM_CORE' : '0xD (SMM_CORE)',
112 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
115 ## The look up table of the supported opcode in the dependency expression binaries
116 gOpCodeList
= ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
119 # Writes a string to the file object.
121 # This function writes a string to the file object and a new line is appended
122 # afterwards. It may optionally wraps the string for better readability.
124 # @File The file object to write
125 # @String The string to be written to the file
126 # @Wrapper Indicates whether to wrap the string
128 def FileWrite(File
, String
, Wrapper
=False):
130 String
= textwrap
.fill(String
, 120)
131 File
.write(String
+ "\r\n")
134 # Find all the header file that the module source directly includes.
136 # This function scans source code to find all header files the module may
137 # include. This is not accurate but very effective to find all the header
138 # file the module might include with #include statement.
140 # @Source The source file name
141 # @IncludePathList The list of include path to find the source file.
142 # @IncludeFiles The dictionary of current found include files.
144 def FindIncludeFiles(Source
, IncludePathList
, IncludeFiles
):
145 FileContents
= open(Source
).read()
147 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
149 for Match
in gIncludePattern
.finditer(FileContents
):
150 FileName
= Match
.group(1).strip()
151 for Dir
in [os
.path
.dirname(Source
)] + IncludePathList
:
152 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
153 if os
.path
.exists(FullFileName
):
154 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
158 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
160 for Match
in gIncludePattern2
.finditer(FileContents
):
162 Type
= Match
.group(1)
163 if "ARCH_PROTOCOL" in Type
:
164 FileName
= "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
165 elif "PROTOCOL" in Type
:
166 FileName
= "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
168 FileName
= "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key
}
170 FileName
= "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key
}
173 for Dir
in IncludePathList
:
174 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
175 if os
.path
.exists(FullFileName
):
176 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
179 ## Split each lines in file
181 # This method is used to split the lines in file to make the length of each line
182 # less than MaxLength.
184 # @param Content The content of file
185 # @param MaxLength The Max Length of the line
187 def FileLinesSplit(Content
=None, MaxLength
=None):
188 ContentList
= Content
.split(TAB_LINE_BREAK
)
191 for Line
in ContentList
:
192 while len(Line
.rstrip()) > MaxLength
:
193 LineSpaceIndex
= Line
.rfind(TAB_SPACE_SPLIT
, 0, MaxLength
)
194 LineSlashIndex
= Line
.rfind(TAB_SLASH
, 0, MaxLength
)
195 LineBackSlashIndex
= Line
.rfind(TAB_BACK_SLASH
, 0, MaxLength
)
196 if max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
) > 0:
197 LineBreakIndex
= max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
)
199 LineBreakIndex
= MaxLength
200 NewContentList
.append(Line
[:LineBreakIndex
])
201 Line
= Line
[LineBreakIndex
:]
203 NewContentList
.append(Line
)
204 for NewLine
in NewContentList
:
205 NewContent
+= NewLine
+ TAB_LINE_BREAK
211 # Parse binary dependency expression section
213 # This utility class parses the dependency expression section and translate the readable
214 # GUID name and value.
216 class DepexParser(object):
218 # Constructor function for class DepexParser
220 # This constructor function collect GUID values so that the readable
221 # GUID name can be translated.
223 # @param self The object pointer
224 # @param Wa Workspace context information
226 def __init__(self
, Wa
):
228 for Pa
in Wa
.AutoGenObjectList
:
229 for Package
in Pa
.PackageList
:
230 for Protocol
in Package
.Protocols
:
231 GuidValue
= GuidStructureStringToGuidString(Package
.Protocols
[Protocol
])
232 self
._GuidDb
[GuidValue
.upper()] = Protocol
233 for Ppi
in Package
.Ppis
:
234 GuidValue
= GuidStructureStringToGuidString(Package
.Ppis
[Ppi
])
235 self
._GuidDb
[GuidValue
.upper()] = Ppi
236 for Guid
in Package
.Guids
:
237 GuidValue
= GuidStructureStringToGuidString(Package
.Guids
[Guid
])
238 self
._GuidDb
[GuidValue
.upper()] = Guid
241 # Parse the binary dependency expression files.
243 # This function parses the binary dependency expression file and translate it
244 # to the instruction list.
246 # @param self The object pointer
247 # @param DepexFileName The file name of binary dependency expression file.
249 def ParseDepexFile(self
, DepexFileName
):
250 DepexFile
= open(DepexFileName
, "rb")
252 OpCode
= DepexFile
.read(1)
254 Statement
= gOpCodeList
[struct
.unpack("B", OpCode
)[0]]
255 if Statement
in ["BEFORE", "AFTER", "PUSH"]:
256 GuidValue
= "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
257 struct
.unpack("LHHBBBBBBBB", DepexFile
.read(16))
258 GuidString
= self
._GuidDb
.get(GuidValue
, GuidValue
)
259 Statement
= "%s %s" % (Statement
, GuidString
)
260 DepexStatement
.append(Statement
)
261 OpCode
= DepexFile
.read(1)
263 return DepexStatement
266 # Reports library information
268 # This class reports the module library subsection in the build report file.
270 class LibraryReport(object):
272 # Constructor function for class LibraryReport
274 # This constructor function generates LibraryReport object for
277 # @param self The object pointer
278 # @param M Module context information
280 def __init__(self
, M
):
281 self
.LibraryList
= []
282 if int(str(M
.AutoGenVersion
), 0) >= 0x00010005:
283 self
._EdkIIModule
= True
285 self
._EdkIIModule
= False
287 for Lib
in M
.DependentLibraryList
:
288 LibInfPath
= str(Lib
)
289 LibClassList
= Lib
.LibraryClass
[0].LibraryClass
290 LibConstructorList
= Lib
.ConstructorList
291 LibDesstructorList
= Lib
.DestructorList
292 LibDepexList
= Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]
293 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
))
296 # Generate report for module library information
298 # This function generates report for the module library.
299 # If the module is EDKII style one, the additional library class, library
300 # constructor/destructor and dependency expression may also be reported.
302 # @param self The object pointer
303 # @param File The file object for report
305 def GenerateReport(self
, File
):
306 FileWrite(File
, gSubSectionStart
)
307 FileWrite(File
, TAB_BRG_LIBRARY
)
308 if len(self
.LibraryList
) > 0:
309 FileWrite(File
, gSubSectionSep
)
310 for LibraryItem
in self
.LibraryList
:
311 LibInfPath
= LibraryItem
[0]
312 FileWrite(File
, LibInfPath
)
315 # Report library class, library constructor and destructor for
316 # EDKII style module.
318 if self
._EdkIIModule
:
319 LibClass
= LibraryItem
[1]
321 LibConstructor
= " ".join(LibraryItem
[2])
323 EdkIILibInfo
+= " C = " + LibConstructor
324 LibDestructor
= " ".join(LibraryItem
[3])
326 EdkIILibInfo
+= " D = " + LibDestructor
327 LibDepex
= " ".join(LibraryItem
[4])
329 EdkIILibInfo
+= " Depex = " + LibDepex
331 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
333 FileWrite(File
, "{%s}" % LibClass
)
335 FileWrite(File
, gSubSectionEnd
)
338 # Reports dependency expression information
340 # This class reports the module dependency expression subsection in the build report file.
342 class DepexReport(object):
344 # Constructor function for class DepexReport
346 # This constructor function generates DepexReport object for
347 # a module. If the module source contains the DXS file (usually EDK
348 # style module), it uses the dependency in DXS file; otherwise,
349 # it uses the dependency expression from its own INF [Depex] section
350 # and then merges with the ones from its dependent library INF.
352 # @param self The object pointer
353 # @param M Module context information
355 def __init__(self
, M
):
357 self
._DepexFileName
= os
.path
.join(M
.BuildDir
, "OUTPUT", M
.Module
.BaseName
+ ".depex")
358 ModuleType
= M
.ModuleType
360 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
362 if ModuleType
in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "UEFI_APPLICATION"]:
365 for Source
in M
.SourceFileList
:
366 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
367 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
369 self
.Depex
= Match
.group(1).strip()
373 self
.Depex
= M
.DepexExpressionList
.get(M
.ModuleType
, "")
374 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
375 if not self
.ModuleDepex
:
376 self
.ModuleDepex
= "(None)"
379 for Lib
in M
.DependentLibraryList
:
380 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
382 LibDepexList
.append("(" + LibDepex
+ ")")
383 self
.LibraryDepex
= " AND ".join(LibDepexList
)
384 if not self
.LibraryDepex
:
385 self
.LibraryDepex
= "(None)"
389 # Generate report for module dependency expression information
391 # This function generates report for the module dependency expression.
393 # @param self The object pointer
394 # @param File The file object for report
395 # @param GlobalDepexParser The platform global Dependency expression parser object
397 def GenerateReport(self
, File
, GlobalDepexParser
):
399 FileWrite(File
, gSubSectionStart
)
400 FileWrite(File
, TAB_DEPEX
)
401 FileWrite(File
, gSubSectionEnd
)
403 FileWrite(File
, gSubSectionStart
)
404 if os
.path
.isfile(self
._DepexFileName
):
406 DepexStatements
= GlobalDepexParser
.ParseDepexFile(self
._DepexFileName
)
407 FileWrite(File
, "Final Dependency Expression (DEPEX) Instructions")
408 for DepexStatement
in DepexStatements
:
409 FileWrite(File
, " %s" % DepexStatement
)
410 FileWrite(File
, gSubSectionSep
)
412 EdkLogger
.warn(None, "Dependency expression file is corrupted", self
._DepexFileName
)
414 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
416 if self
.Source
== "INF":
417 FileWrite(File
, "%s" % self
.Depex
, True)
418 FileWrite(File
, gSubSectionSep
)
419 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
420 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
422 FileWrite(File
, "%s" % self
.Depex
)
423 FileWrite(File
, gSubSectionEnd
)
426 # Reports dependency expression information
428 # This class reports the module build flags subsection in the build report file.
430 class BuildFlagsReport(object):
432 # Constructor function for class BuildFlagsReport
434 # This constructor function generates BuildFlagsReport object for
435 # a module. It reports the build tool chain tag and all relevant
436 # build flags to build the module.
438 # @param self The object pointer
439 # @param M Module context information
441 def __init__(self
, M
):
444 # Add build flags according to source file extension so that
445 # irrelevant ones can be filtered out.
447 for Source
in M
.SourceFileList
:
448 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
449 if Ext
in [".c", ".cc", ".cpp"]:
450 BuildOptions
["CC"] = 1
451 elif Ext
in [".s", ".asm"]:
452 BuildOptions
["PP"] = 1
453 BuildOptions
["ASM"] = 1
454 elif Ext
in [".vfr"]:
455 BuildOptions
["VFRPP"] = 1
456 BuildOptions
["VFR"] = 1
457 elif Ext
in [".dxs"]:
458 BuildOptions
["APP"] = 1
459 BuildOptions
["CC"] = 1
460 elif Ext
in [".asl"]:
461 BuildOptions
["ASLPP"] = 1
462 BuildOptions
["ASL"] = 1
463 elif Ext
in [".aslc"]:
464 BuildOptions
["ASLCC"] = 1
465 BuildOptions
["ASLDLINK"] = 1
466 BuildOptions
["CC"] = 1
467 elif Ext
in [".asm16"]:
468 BuildOptions
["ASMLINK"] = 1
469 BuildOptions
["SLINK"] = 1
470 BuildOptions
["DLINK"] = 1
473 # Save module build flags.
475 self
.ToolChainTag
= M
.ToolChain
477 for Tool
in BuildOptions
:
478 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
481 # Generate report for module build flags information
483 # This function generates report for the module build flags expression.
485 # @param self The object pointer
486 # @param File The file object for report
488 def GenerateReport(self
, File
):
489 FileWrite(File
, gSubSectionStart
)
490 FileWrite(File
, "Build Flags")
491 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
492 for Tool
in self
.BuildFlags
:
493 FileWrite(File
, gSubSectionSep
)
494 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
496 FileWrite(File
, gSubSectionEnd
)
500 # Reports individual module information
502 # This class reports the module section in the build report file.
503 # It comprises of module summary, module PCD, library, dependency expression,
504 # build flags sections.
506 class ModuleReport(object):
508 # Constructor function for class ModuleReport
510 # This constructor function generates ModuleReport object for
511 # a separate module in a platform build.
513 # @param self The object pointer
514 # @param M Module context information
515 # @param ReportType The kind of report items in the final report file
517 def __init__(self
, M
, ReportType
):
518 self
.ModuleName
= M
.Module
.BaseName
519 self
.ModuleInfPath
= M
.MetaFile
.File
520 self
.FileGuid
= M
.Guid
522 self
.BuildTimeStamp
= None
525 ModuleType
= M
.ModuleType
527 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
529 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
531 if ModuleType
== "DXE_SMM_DRIVER":
532 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
533 if int(PiSpec
, 0) >= 0x0001000A:
534 ModuleType
= "SMM_DRIVER"
535 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
536 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
537 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
538 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
539 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
540 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
542 self
._BuildDir
= M
.BuildDir
543 self
.ModulePcdSet
= {}
544 if "PCD" in ReportType
:
546 # Collect all module used PCD set: module INF referenced directly or indirectly.
547 # It also saves module INF default values of them in case they exist.
549 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
550 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
552 self
.LibraryReport
= None
553 if "LIBRARY" in ReportType
:
554 self
.LibraryReport
= LibraryReport(M
)
556 self
.DepexReport
= None
557 if "DEPEX" in ReportType
:
558 self
.DepexReport
= DepexReport(M
)
560 if "BUILD_FLAGS" in ReportType
:
561 self
.BuildFlagsReport
= BuildFlagsReport(M
)
565 # Generate report for module information
567 # This function generates report for separate module expression
568 # in a platform build.
570 # @param self The object pointer
571 # @param File The file object for report
572 # @param GlobalPcdReport The platform global PCD report object
573 # @param GlobalPredictionReport The platform global Prediction report object
574 # @param GlobalDepexParser The platform global Dependency expression parser object
575 # @param ReportType The kind of report items in the final report file
577 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, GlobalDepexParser
, ReportType
):
578 FileWrite(File
, gSectionStart
)
580 FwReportFileName
= os
.path
.join(self
._BuildDir
, "DEBUG", self
.ModuleName
+ ".txt")
581 if os
.path
.isfile(FwReportFileName
):
583 FileContents
= open(FwReportFileName
).read()
584 Match
= gModuleSizePattern
.search(FileContents
)
586 self
.Size
= int(Match
.group(1))
588 Match
= gTimeStampPattern
.search(FileContents
)
590 self
.BuildTimeStamp
= datetime
.fromtimestamp(int(Match
.group(1)))
592 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
594 FileWrite(File
, "Module Summary")
595 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
596 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
597 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
599 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
600 if self
.BuildTimeStamp
:
601 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
603 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
604 if self
.UefiSpecVersion
:
605 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
606 if self
.PiSpecVersion
:
607 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
609 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
611 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
612 if self
.PciClassCode
:
613 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
615 FileWrite(File
, gSectionSep
)
617 if "PCD" in ReportType
:
618 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
620 if "LIBRARY" in ReportType
:
621 self
.LibraryReport
.GenerateReport(File
)
623 if "DEPEX" in ReportType
:
624 self
.DepexReport
.GenerateReport(File
, GlobalDepexParser
)
626 if "BUILD_FLAGS" in ReportType
:
627 self
.BuildFlagsReport
.GenerateReport(File
)
629 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
630 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
632 FileWrite(File
, gSectionEnd
)
635 # Reports platform and module PCD information
637 # This class reports the platform PCD section and module PCD subsection
638 # in the build report file.
640 class PcdReport(object):
642 # Constructor function for class PcdReport
644 # This constructor function generates PcdReport object a platform build.
645 # It collects the whole PCD database from platform DSC files, platform
646 # flash description file and package DEC files.
648 # @param self The object pointer
649 # @param Wa Workspace context information
651 def __init__(self
, Wa
):
655 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
659 self
.ModulePcdOverride
= {}
660 for Pa
in Wa
.AutoGenObjectList
:
662 # Collect all platform referenced PCDs and grouped them by PCD token space
665 for Pcd
in Pa
.AllPcdList
:
666 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
667 if Pcd
not in PcdList
:
669 if len(Pcd
.TokenCName
) > self
.MaxLen
:
670 self
.MaxLen
= len(Pcd
.TokenCName
)
672 for Module
in Pa
.Platform
.Modules
.values():
674 # Collect module override PCDs
676 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
677 TokenCName
= ModulePcd
.TokenCName
678 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
679 ModuleDefault
= ModulePcd
.DefaultValue
680 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
681 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
685 # Collect PCD DEC default value.
687 self
.DecPcdDefault
= {}
688 for Pa
in Wa
.AutoGenObjectList
:
689 for Package
in Pa
.PackageList
:
690 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
691 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
692 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
694 # Collect PCDs defined in DSC common section
696 self
.DscPcdDefault
= {}
697 for Platform
in Wa
.BuildDatabase
.WorkspaceDb
.PlatformList
:
698 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
699 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
701 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
704 # Generate report for PCD information
706 # This function generates report for separate module expression
707 # in a platform build.
709 # @param self The object pointer
710 # @param File The file object for report
711 # @param ModulePcdSet Set of all PCDs referenced by module or None for
712 # platform PCD report
713 # @param DscOverridePcds Module DSC override PCDs set
715 def GenerateReport(self
, File
, ModulePcdSet
):
716 if ModulePcdSet
== None:
718 # For platform global PCD section
720 FileWrite(File
, gSectionStart
)
721 FileWrite(File
, "Platform Configuration Database Report")
722 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
723 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
724 FileWrite(File
, " *M - Module scoped PCD override")
725 FileWrite(File
, gSectionSep
)
728 # For module PCD sub-section
730 FileWrite(File
, gSubSectionStart
)
731 FileWrite(File
, TAB_BRG_PCD
)
732 FileWrite(File
, gSubSectionSep
)
734 for Key
in self
.AllPcds
:
736 # Group PCD by their token space GUID C Name
739 for Type
in self
.AllPcds
[Key
]:
741 # Group PCD by their usage type
743 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
744 for Pcd
in self
.AllPcds
[Key
][Type
]:
746 # Get PCD default value and their override relationship
748 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
749 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
750 DscDefaultValue
= self
.FdfPcdSet
.get((Pcd
.TokenCName
, Key
), DscDefaultValue
)
751 InfDefaultValue
= None
753 PcdValue
= DecDefaultValue
755 PcdValue
= DscDefaultValue
756 if ModulePcdSet
!= None:
757 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
759 InfDefault
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
763 if ModulePcdSet
== None:
769 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
770 PcdValueNumber
= int(PcdValue
.strip(), 0)
771 if DecDefaultValue
== None:
774 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
775 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
777 if InfDefaultValue
== None:
780 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
781 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
783 if DscDefaultValue
== None:
786 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
787 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
789 if DecDefaultValue
== None:
792 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
794 if InfDefaultValue
== None:
797 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
799 if DscDefaultValue
== None:
802 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
805 # Report PCD item according to their override relationship
807 if DecMatch
and InfMatch
:
808 FileWrite(File
, ' %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
811 if (Pcd
.TokenCName
, Key
) in self
.FdfPcdSet
:
812 FileWrite(File
, ' *F %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
814 FileWrite(File
, ' *P %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
816 FileWrite(File
, ' *M %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '('+Pcd
.DatumType
+')', PcdValue
.strip()))
818 if TypeName
in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):
819 for SkuInfo
in Pcd
.SkuInfoList
.values():
820 if TypeName
in ('DYNHII', 'DEXHII'):
821 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
823 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
825 if not DscMatch
and DscDefaultValue
!= None:
826 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', DscDefaultValue
.strip()))
828 if not InfMatch
and InfDefaultValue
!= None:
829 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', InfDefaultValue
.strip()))
831 if not DecMatch
and DecDefaultValue
!= None:
832 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', DecDefaultValue
.strip()))
834 if ModulePcdSet
== None:
835 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
836 for ModulePath
in ModuleOverride
:
837 ModuleDefault
= ModuleOverride
[ModulePath
]
838 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
839 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
840 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
842 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
845 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 19, ModulePath
, ModuleDefault
.strip()))
847 if ModulePcdSet
== None:
848 FileWrite(File
, gSectionEnd
)
850 FileWrite(File
, gSubSectionEnd
)
855 # Reports platform and module Prediction information
857 # This class reports the platform execution order prediction section and
858 # module load fixed address prediction subsection in the build report file.
860 class PredictionReport(object):
862 # Constructor function for class PredictionReport
864 # This constructor function generates PredictionReport object for the platform.
866 # @param self: The object pointer
867 # @param Wa Workspace context information
869 def __init__(self
, Wa
):
870 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
871 self
._MapFileParsed
= False
872 self
._EotToolInvoked
= False
873 self
._FvDir
= Wa
.FvDir
874 self
._EotDir
= Wa
.BuildDir
875 self
._FfsEntryPoint
= {}
877 self
._SourceList
= []
878 self
.FixedMapDict
= {}
883 # Collect all platform reference source files and GUID C Name
885 for Pa
in Wa
.AutoGenObjectList
:
886 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
888 # BASE typed modules are EFI agnostic, so we need not scan
889 # their source code to find PPI/Protocol produce or consume
892 if Module
.ModuleType
== "BASE":
895 # Add module referenced source files
897 self
._SourceList
.append(str(Module
))
899 for Source
in Module
.SourceFileList
:
900 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
901 self
._SourceList
.append(" " + str(Source
))
902 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
903 for IncludeFile
in IncludeList
.values():
904 self
._SourceList
.append(" " + IncludeFile
)
906 for Guid
in Module
.PpiList
:
907 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
908 for Guid
in Module
.ProtocolList
:
909 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
910 for Guid
in Module
.GuidList
:
911 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
913 if Module
.Guid
and not Module
.IsLibrary
:
914 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
915 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
916 RealEntryPoint
= "_ModuleEntryPoint"
918 RealEntryPoint
= EntryPoint
919 if EntryPoint
== "_ModuleEntryPoint":
920 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
921 Match
= gGlueLibEntryPoint
.search(CCFlags
)
923 EntryPoint
= Match
.group(1)
925 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
929 # Collect platform firmware volume list as the input of EOT.
933 for Fd
in Wa
.FdfProfile
.FdDict
:
934 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
935 if FdRegion
.RegionType
!= "FV":
937 for FvName
in FdRegion
.RegionDataList
:
938 if FvName
in self
._FvList
:
940 self
._FvList
.append(FvName
)
941 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
942 for Section
in Ffs
.SectionList
:
944 for FvSection
in Section
.SectionList
:
945 if FvSection
.FvName
in self
._FvList
:
947 self
._FvList
.append(FvSection
.FvName
)
948 except AttributeError:
953 # Parse platform fixed address map files
955 # This function parses the platform final fixed address map file to get
956 # the database of predicted fixed address for module image base, entry point
959 # @param self: The object pointer
961 def _ParseMapFile(self
):
962 if self
._MapFileParsed
:
964 self
._MapFileParsed
= True
965 if os
.path
.isfile(self
._MapFileName
):
967 FileContents
= open(self
._MapFileName
).read()
968 for Match
in gMapFileItemPattern
.finditer(FileContents
):
969 AddressType
= Match
.group(1)
970 BaseAddress
= Match
.group(2)
971 EntryPoint
= Match
.group(3)
972 Guid
= Match
.group(4).upper()
973 List
= self
.FixedMapDict
.setdefault(Guid
, [])
974 List
.append((AddressType
, BaseAddress
, "*I"))
975 List
.append((AddressType
, EntryPoint
, "*E"))
977 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
980 # Invokes EOT tool to get the predicted the execution order.
982 # This function invokes EOT tool to calculate the predicted dispatch order
984 # @param self: The object pointer
986 def _InvokeEotTool(self
):
987 if self
._EotToolInvoked
:
990 self
._EotToolInvoked
= True
992 for FvName
in self
._FvList
:
993 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
994 if os
.path
.isfile(FvFile
):
995 FvFileList
.append(FvFile
)
997 if len(FvFileList
) == 0:
1000 # Write source file list and GUID file list to an intermediate file
1001 # as the input for EOT tool and dispatch List as the output file
1004 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
1005 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
1006 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
1008 TempFile
= open(SourceList
, "w+")
1009 for Item
in self
._SourceList
:
1010 FileWrite(TempFile
, Item
)
1012 TempFile
= open(GuidList
, "w+")
1013 for Key
in self
._GuidMap
:
1014 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
1018 from Eot
.Eot
import Eot
1021 # Invoke EOT tool and echo its runtime performance
1023 EotStartTime
= time
.time()
1024 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
1025 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
1026 EotEndTime
= time
.time()
1027 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
1028 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
1031 # Parse the output of EOT tool
1033 for Line
in open(DispatchList
):
1034 if len(Line
.split()) < 4:
1036 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
1037 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
1038 if len(Symbol
) > self
.MaxLen
:
1039 self
.MaxLen
= len(Symbol
)
1040 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
1042 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1043 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1047 # Generate platform execution order report
1049 # This function generates the predicted module execution order.
1051 # @param self The object pointer
1052 # @param File The file object for report
1054 def _GenerateExecutionOrderReport(self
, File
):
1055 self
._InvokeEotTool
()
1056 if len(self
.ItemList
) == 0:
1058 FileWrite(File
, gSectionStart
)
1059 FileWrite(File
, "Execution Order Prediction")
1060 FileWrite(File
, "*P PEI phase")
1061 FileWrite(File
, "*D DXE phase")
1062 FileWrite(File
, "*E Module INF entry point name")
1063 FileWrite(File
, "*N Module notification function name")
1065 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1066 FileWrite(File
, gSectionSep
)
1067 for Item
in self
.ItemList
:
1068 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1070 FileWrite(File
, gSectionStart
)
1073 # Generate Fixed Address report.
1075 # This function generate the predicted fixed address report for a module
1076 # specified by Guid.
1078 # @param self The object pointer
1079 # @param File The file object for report
1080 # @param Guid The module Guid value.
1081 # @param NotifyList The list of all notify function in a module
1083 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1084 self
._ParseMapFile
()
1085 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1086 if not FixedAddressList
:
1089 FileWrite(File
, gSubSectionStart
)
1090 FileWrite(File
, "Fixed Address Prediction")
1091 FileWrite(File
, "*I Image Loading Address")
1092 FileWrite(File
, "*E Entry Point Address")
1093 FileWrite(File
, "*N Notification Function Address")
1094 FileWrite(File
, "*F Flash Address")
1095 FileWrite(File
, "*M Memory Address")
1096 FileWrite(File
, "*S SMM RAM Offset")
1097 FileWrite(File
, "TOM Top of Memory")
1099 FileWrite(File
, "Type Address Name")
1100 FileWrite(File
, gSubSectionSep
)
1101 for Item
in FixedAddressList
:
1106 Name
= "(Image Base)"
1107 elif Symbol
== "*E":
1108 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1109 elif Symbol
in NotifyList
:
1117 elif "Memory" in Type
:
1123 Value
= "TOM" + Value
1125 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1128 # Generate report for the prediction part
1130 # This function generate the predicted fixed address report for a module or
1131 # predicted module execution order for a platform.
1132 # If the input Guid is None, then, it generates the predicted module execution order;
1133 # otherwise it generated the module fixed loading address for the module specified by
1136 # @param self The object pointer
1137 # @param File The file object for report
1138 # @param Guid The module Guid value.
1140 def GenerateReport(self
, File
, Guid
):
1142 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1144 self
._GenerateExecutionOrderReport
(File
)
1147 # Reports FD region information
1149 # This class reports the FD subsection in the build report file.
1150 # It collects region information of platform flash device.
1151 # If the region is a firmware volume, it lists the set of modules
1152 # and its space information; otherwise, it only lists its region name,
1153 # base address and size in its sub-section header.
1154 # If there are nesting FVs, the nested FVs will list immediate after
1155 # this FD region subsection
1157 class FdRegionReport(object):
1159 # Discover all the nested FV name list.
1161 # This is an internal worker function to discover the all the nested FV information
1162 # in the parent firmware volume. It uses deep first search algorithm recursively to
1163 # find all the FV list name and append them to the list.
1165 # @param self The object pointer
1166 # @param FvName The name of current firmware file system
1167 # @param Wa Workspace context information
1169 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1170 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1171 for Section
in Ffs
.SectionList
:
1173 for FvSection
in Section
.SectionList
:
1174 if FvSection
.FvName
in self
.FvList
:
1176 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1177 self
.FvList
.append(FvSection
.FvName
)
1178 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1179 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1180 except AttributeError:
1184 # Constructor function for class FdRegionReport
1186 # This constructor function generates FdRegionReport object for a specified FdRegion.
1187 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1188 # volume list. This function also collects GUID map in order to dump module identification
1189 # in the final report.
1191 # @param self: The object pointer
1192 # @param FdRegion The current FdRegion object
1193 # @param Wa Workspace context information
1195 def __init__(self
, FdRegion
, Wa
):
1196 self
.Type
= FdRegion
.RegionType
1197 self
.BaseAddress
= FdRegion
.Offset
1198 self
.Size
= FdRegion
.Size
1202 self
._FvDir
= Wa
.FvDir
1205 # If the input FdRegion is not a firmware volume,
1208 if self
.Type
!= "FV":
1212 # Find all nested FVs in the FdRegion
1214 for FvName
in FdRegion
.RegionDataList
:
1215 if FvName
in self
.FvList
:
1217 self
.FvList
.append(FvName
)
1218 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1219 self
._DiscoverNestedFvList
(FvName
, Wa
)
1223 # Collect PCDs declared in DEC files.
1225 for Pa
in Wa
.AutoGenObjectList
:
1226 for Package
in Pa
.PackageList
:
1227 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1228 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1229 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1231 # Collect PCDs defined in DSC common section
1233 for Platform
in Wa
.BuildDatabase
.WorkspaceDb
.PlatformList
:
1234 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
1235 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1236 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1239 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1241 self
._GuidsDb
["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
1242 self
._GuidsDb
["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"
1244 # Add ACPI table storage file
1246 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1248 for Pa
in Wa
.AutoGenObjectList
:
1249 for ModuleKey
in Pa
.Platform
.Modules
:
1250 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1251 InfPath
= os
.path
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1252 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1255 # Collect the GUID map in the FV firmware volume
1257 for FvName
in self
.FvList
:
1258 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1261 # collect GUID map for binary EFI file in FDF file.
1263 Guid
= Ffs
.NameGuid
.upper()
1264 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1266 PcdTokenspace
= Match
.group(1)
1267 PcdToken
= Match
.group(2)
1268 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1269 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1270 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1271 for Section
in Ffs
.SectionList
:
1273 ModuleSectFile
= os
.path
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1274 self
._GuidsDb
[Guid
] = ModuleSectFile
1275 except AttributeError:
1277 except AttributeError:
1282 # Internal worker function to generate report for the FD region
1284 # This internal worker function to generate report for the FD region.
1285 # It the type is firmware volume, it lists offset and module identification.
1287 # @param self The object pointer
1288 # @param File The file object for report
1289 # @param Title The title for the FD subsection
1290 # @param BaseAddress The base address for the FD region
1291 # @param Size The size of the FD region
1292 # @param FvName The FV name if the FD region is a firmware volume
1294 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1295 FileWrite(File
, gSubSectionStart
)
1296 FileWrite(File
, Title
)
1297 FileWrite(File
, "Type: %s" % Type
)
1298 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1300 if self
.Type
== "FV":
1304 FvReportFileName
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv.txt")
1307 # Collect size info in the firmware volume.
1309 FvReport
= open(FvReportFileName
).read()
1310 Match
= gFvTotalSizePattern
.search(FvReport
)
1312 FvTotalSize
= int(Match
.group(1), 16)
1313 Match
= gFvTakenSizePattern
.search(FvReport
)
1315 FvTakenSize
= int(Match
.group(1), 16)
1316 FvFreeSize
= FvTotalSize
- FvTakenSize
1318 # Write size information to the report file.
1320 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1321 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1322 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1323 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1324 FileWrite(File
, "Offset Module")
1325 FileWrite(File
, gSubSectionSep
)
1327 # Write module offset and module identification to the report file.
1330 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1331 Guid
= Match
.group(2).upper()
1332 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1333 OffsetList
= OffsetInfo
.keys()
1335 for Offset
in OffsetList
:
1336 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1338 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1340 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1341 FileWrite(File
, gSubSectionEnd
)
1344 # Generate report for the FD region
1346 # This function generates report for the FD region.
1348 # @param self The object pointer
1349 # @param File The file object for report
1351 def GenerateReport(self
, File
):
1352 if (len(self
.FvList
) > 0):
1353 for FvItem
in self
.FvList
:
1354 Info
= self
.FvInfo
[FvItem
]
1355 self
._GenerateReport
(File
, Info
[0], "FV", Info
[1], Info
[2], FvItem
)
1357 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
1360 # Reports FD information
1362 # This class reports the FD section in the build report file.
1363 # It collects flash device information for a platform.
1365 class FdReport(object):
1367 # Constructor function for class FdReport
1369 # This constructor function generates FdReport object for a specified
1372 # @param self The object pointer
1373 # @param Fd The current Firmware device object
1374 # @param Wa Workspace context information
1376 def __init__(self
, Fd
, Wa
):
1377 self
.FdName
= Fd
.FdUiName
1378 self
.BaseAddress
= Fd
.BaseAddress
1380 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
1383 # Generate report for the firmware device.
1385 # This function generates report for the firmware device.
1387 # @param self The object pointer
1388 # @param File The file object for report
1390 def GenerateReport(self
, File
):
1391 FileWrite(File
, gSectionStart
)
1392 FileWrite(File
, "Firmware Device (FD)")
1393 FileWrite(File
, "FD Name: %s" % self
.FdName
)
1394 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
1395 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
1396 if len(self
.FdRegionList
) > 0:
1397 FileWrite(File
, gSectionSep
)
1398 for FdRegionItem
in self
.FdRegionList
:
1399 FdRegionItem
.GenerateReport(File
)
1401 FileWrite(File
, gSectionEnd
)
1406 # Reports platform information
1408 # This class reports the whole platform information
1410 class PlatformReport(object):
1412 # Constructor function for class PlatformReport
1414 # This constructor function generates PlatformReport object a platform build.
1415 # It generates report for platform summary, flash, global PCDs and detailed
1416 # module information for modules involved in platform build.
1418 # @param self The object pointer
1419 # @param Wa Workspace context information
1420 # @param MaList The list of modules in the platform build
1422 def __init__(self
, Wa
, MaList
, ReportType
):
1423 self
._WorkspaceDir
= Wa
.WorkspaceDir
1424 self
.PlatformName
= Wa
.Name
1425 self
.PlatformDscPath
= Wa
.Platform
1426 self
.Architectures
= " ".join(Wa
.ArchList
)
1427 self
.ToolChain
= Wa
.ToolChain
1428 self
.Target
= Wa
.BuildTarget
1429 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
1430 self
.BuildEnvironment
= platform
.platform()
1432 self
.PcdReport
= None
1433 if "PCD" in ReportType
:
1434 self
.PcdReport
= PcdReport(Wa
)
1436 self
.FdReportList
= []
1437 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
== None:
1438 for Fd
in Wa
.FdfProfile
.FdDict
:
1439 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
1441 self
.PredictionReport
= None
1442 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
1443 self
.PredictionReport
= PredictionReport(Wa
)
1445 self
.DepexParser
= None
1446 if "DEPEX" in ReportType
:
1447 self
.DepexParser
= DepexParser(Wa
)
1449 self
.ModuleReportList
= []
1451 self
._IsModuleBuild
= True
1453 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
1455 self
._IsModuleBuild
= False
1456 for Pa
in Wa
.AutoGenObjectList
:
1457 for ModuleKey
in Pa
.Platform
.Modules
:
1458 self
.ModuleReportList
.append(ModuleReport(Pa
.Platform
.Modules
[ModuleKey
].M
, ReportType
))
1463 # Generate report for the whole platform.
1465 # This function generates report for platform information.
1466 # It comprises of platform summary, global PCD, flash and
1467 # module list sections.
1469 # @param self The object pointer
1470 # @param File The file object for report
1471 # @param BuildDuration The total time to build the modules
1472 # @param ReportType The kind of report items in the final report file
1474 def GenerateReport(self
, File
, BuildDuration
, ReportType
):
1475 FileWrite(File
, "Platform Summary")
1476 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
1477 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
1478 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
1479 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
1480 FileWrite(File
, "Target: %s" % self
.Target
)
1481 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
1482 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
1483 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
1484 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
1486 if not self
._IsModuleBuild
:
1487 if "PCD" in ReportType
:
1488 self
.PcdReport
.GenerateReport(File
, None)
1490 if "FLASH" in ReportType
:
1491 for FdReportListItem
in self
.FdReportList
:
1492 FdReportListItem
.GenerateReport(File
)
1494 for ModuleReportItem
in self
.ModuleReportList
:
1495 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
1497 if not self
._IsModuleBuild
:
1498 if "EXECUTION_ORDER" in ReportType
:
1499 self
.PredictionReport
.GenerateReport(File
, None)
1501 ## BuildReport class
1503 # This base class contain the routines to collect data and then
1504 # applies certain format to the output report
1506 class BuildReport(object):
1508 # Constructor function for class BuildReport
1510 # This constructor function generates BuildReport object a platform build.
1511 # It generates report for platform summary, flash, global PCDs and detailed
1512 # module information for modules involved in platform build.
1514 # @param self The object pointer
1515 # @param ReportFile The file name to save report file
1516 # @param ReportType The kind of report items in the final report file
1518 def __init__(self
, ReportFile
, ReportType
):
1519 self
.ReportFile
= ReportFile
1521 self
.ReportList
= []
1522 self
.ReportType
= []
1524 for ReportTypeItem
in ReportType
:
1525 if ReportTypeItem
not in self
.ReportType
:
1526 self
.ReportType
.append(ReportTypeItem
)
1528 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "FLASH", "FIXED_ADDRESS"]
1530 # Adds platform report to the list
1532 # This function adds a platform report to the final report list.
1534 # @param self The object pointer
1535 # @param Wa Workspace context information
1536 # @param MaList The list of modules in the platform build
1538 def AddPlatformReport(self
, Wa
, MaList
=None):
1540 self
.ReportList
.append((Wa
, MaList
))
1543 # Generates the final report.
1545 # This function generates platform build report. It invokes GenerateReport()
1546 # method for every platform report in the list.
1548 # @param self The object pointer
1549 # @param BuildDuration The total time to build the modules
1551 def GenerateReport(self
, BuildDuration
):
1555 for (Wa
, MaList
) in self
.ReportList
:
1556 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, self
.ReportType
)
1557 Content
= FileLinesSplit(File
.getvalue(), gLineMaxLength
)
1558 SaveFileOnChange(self
.ReportFile
, Content
, True)
1559 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
1561 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
1563 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
1564 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1567 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1568 if __name__
== '__main__':