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 - 2016, 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.
19 import Common
.LongFilePathOs
as os
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
43 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
44 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
45 import Common
.GlobalData
as GlobalData
47 ## Pattern to extract contents in EDK DXS files
48 gDxsDependencyPattern
= re
.compile(r
"DEPENDENCY_START(.+)DEPENDENCY_END", re
.DOTALL
)
50 ## Pattern to find total FV total size, occupied size in flash report intermediate file
51 gFvTotalSizePattern
= re
.compile(r
"EFI_FV_TOTAL_SIZE = (0x[0-9a-fA-F]+)")
52 gFvTakenSizePattern
= re
.compile(r
"EFI_FV_TAKEN_SIZE = (0x[0-9a-fA-F]+)")
54 ## Pattern to find module size and time stamp in module summary report intermediate file
55 gModuleSizePattern
= re
.compile(r
"MODULE_SIZE = (\d+)")
56 gTimeStampPattern
= re
.compile(r
"TIME_STAMP = (\d+)")
58 ## Pattern to find GUID value in flash description files
59 gPcdGuidPattern
= re
.compile(r
"PCD\((\w+)[.](\w+)\)")
61 ## Pattern to collect offset, GUID value pair in the flash report intermediate file
62 gOffsetGuidPattern
= re
.compile(r
"(0x[0-9A-Fa-f]+) ([-A-Fa-f0-9]+)")
64 ## Pattern to find module base address and entry point in fixed flash map file
65 gModulePattern
= r
"\n[-\w]+\s*\(([^,]+),\s*BaseAddress=%(Address)s,\s*EntryPoint=%(Address)s\)\s*\(GUID=([-0-9A-Fa-f]+)[^)]*\)"
66 gMapFileItemPattern
= re
.compile(gModulePattern
% {"Address" : "(-?0[xX][0-9A-Fa-f]+)"})
68 ## Pattern to find all module referenced header files in source files
69 gIncludePattern
= re
.compile(r
'#include\s*["<]([^">]+)[">]')
70 gIncludePattern2
= re
.compile(r
"#include\s+EFI_([A-Z_]+)\s*[(]\s*(\w+)\s*[)]")
72 ## Pattern to find the entry point for EDK module using EDKII Glue library
73 gGlueLibEntryPoint
= re
.compile(r
"__EDKII_GLUE_MODULE_ENTRY_POINT__\s*=\s*(\w+)")
75 ## Tags for MaxLength of line in report
78 ## Tags for end of line in report
81 ## Tags for section start, end and separator
82 gSectionStart
= ">" + "=" * (gLineMaxLength
- 2) + "<"
83 gSectionEnd
= "<" + "=" * (gLineMaxLength
- 2) + ">" + "\n"
84 gSectionSep
= "=" * gLineMaxLength
86 ## Tags for subsection start, end and separator
87 gSubSectionStart
= ">" + "-" * (gLineMaxLength
- 2) + "<"
88 gSubSectionEnd
= "<" + "-" * (gLineMaxLength
- 2) + ">"
89 gSubSectionSep
= "-" * gLineMaxLength
92 ## The look up table to map PCD type to pair of report display type and DEC type
94 'FixedAtBuild' : ('FIXED', 'FixedAtBuild'),
95 'PatchableInModule': ('PATCH', 'PatchableInModule'),
96 'FeatureFlag' : ('FLAG', 'FeatureFlag'),
97 'Dynamic' : ('DYN', 'Dynamic'),
98 'DynamicHii' : ('DYNHII', 'Dynamic'),
99 'DynamicVpd' : ('DYNVPD', 'Dynamic'),
100 'DynamicEx' : ('DEX', 'DynamicEx'),
101 'DynamicExHii' : ('DEXHII', 'DynamicEx'),
102 'DynamicExVpd' : ('DEXVPD', 'DynamicEx'),
105 ## The look up table to map module type to driver type
107 'SEC' : '0x3 (SECURITY_CORE)',
108 'PEI_CORE' : '0x4 (PEI_CORE)',
109 'PEIM' : '0x6 (PEIM)',
110 'DXE_CORE' : '0x5 (DXE_CORE)',
111 'DXE_DRIVER' : '0x7 (DRIVER)',
112 'DXE_SAL_DRIVER' : '0x7 (DRIVER)',
113 'DXE_SMM_DRIVER' : '0x7 (DRIVER)',
114 'DXE_RUNTIME_DRIVER': '0x7 (DRIVER)',
115 'UEFI_DRIVER' : '0x7 (DRIVER)',
116 'UEFI_APPLICATION' : '0x9 (APPLICATION)',
117 'SMM_CORE' : '0xD (SMM_CORE)',
118 'SMM_DRIVER' : '0xA (SMM)', # Extension of module type to support PI 1.1 SMM drivers
121 ## The look up table of the supported opcode in the dependency expression binaries
122 gOpCodeList
= ["BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"]
125 # Writes a string to the file object.
127 # This function writes a string to the file object and a new line is appended
128 # afterwards. It may optionally wraps the string for better readability.
130 # @File The file object to write
131 # @String The string to be written to the file
132 # @Wrapper Indicates whether to wrap the string
134 def FileWrite(File
, String
, Wrapper
=False):
136 String
= textwrap
.fill(String
, 120)
137 File
.write(String
+ gEndOfLine
)
140 # Find all the header file that the module source directly includes.
142 # This function scans source code to find all header files the module may
143 # include. This is not accurate but very effective to find all the header
144 # file the module might include with #include statement.
146 # @Source The source file name
147 # @IncludePathList The list of include path to find the source file.
148 # @IncludeFiles The dictionary of current found include files.
150 def FindIncludeFiles(Source
, IncludePathList
, IncludeFiles
):
151 FileContents
= open(Source
).read()
153 # Find header files with pattern #include "XXX.h" or #include <XXX.h>
155 for Match
in gIncludePattern
.finditer(FileContents
):
156 FileName
= Match
.group(1).strip()
157 for Dir
in [os
.path
.dirname(Source
)] + IncludePathList
:
158 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
159 if os
.path
.exists(FullFileName
):
160 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
164 # Find header files with pattern like #include EFI_PPI_CONSUMER(XXX)
166 for Match
in gIncludePattern2
.finditer(FileContents
):
168 Type
= Match
.group(1)
169 if "ARCH_PROTOCOL" in Type
:
170 FileName
= "ArchProtocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
171 elif "PROTOCOL" in Type
:
172 FileName
= "Protocol/%(Key)s/%(Key)s.h" % {"Key" : Key
}
174 FileName
= "Ppi/%(Key)s/%(Key)s.h" % {"Key" : Key
}
176 FileName
= "Guid/%(Key)s/%(Key)s.h" % {"Key" : Key
}
179 for Dir
in IncludePathList
:
180 FullFileName
= os
.path
.normpath(os
.path
.join(Dir
, FileName
))
181 if os
.path
.exists(FullFileName
):
182 IncludeFiles
[FullFileName
.lower().replace("\\", "/")] = FullFileName
185 ## Split each lines in file
187 # This method is used to split the lines in file to make the length of each line
188 # less than MaxLength.
190 # @param Content The content of file
191 # @param MaxLength The Max Length of the line
193 def FileLinesSplit(Content
=None, MaxLength
=None):
194 ContentList
= Content
.split(TAB_LINE_BREAK
)
197 for Line
in ContentList
:
198 while len(Line
.rstrip()) > MaxLength
:
199 LineSpaceIndex
= Line
.rfind(TAB_SPACE_SPLIT
, 0, MaxLength
)
200 LineSlashIndex
= Line
.rfind(TAB_SLASH
, 0, MaxLength
)
201 LineBackSlashIndex
= Line
.rfind(TAB_BACK_SLASH
, 0, MaxLength
)
202 if max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
) > 0:
203 LineBreakIndex
= max(LineSpaceIndex
, LineSlashIndex
, LineBackSlashIndex
)
205 LineBreakIndex
= MaxLength
206 NewContentList
.append(Line
[:LineBreakIndex
])
207 Line
= Line
[LineBreakIndex
:]
209 NewContentList
.append(Line
)
210 for NewLine
in NewContentList
:
211 NewContent
+= NewLine
+ TAB_LINE_BREAK
213 NewContent
= NewContent
.replace(TAB_LINE_BREAK
, gEndOfLine
).replace('\r\r\n', gEndOfLine
)
219 # Parse binary dependency expression section
221 # This utility class parses the dependency expression section and translate the readable
222 # GUID name and value.
224 class DepexParser(object):
226 # Constructor function for class DepexParser
228 # This constructor function collect GUID values so that the readable
229 # GUID name can be translated.
231 # @param self The object pointer
232 # @param Wa Workspace context information
234 def __init__(self
, Wa
):
236 for Pa
in Wa
.AutoGenObjectList
:
237 for Package
in Pa
.PackageList
:
238 for Protocol
in Package
.Protocols
:
239 GuidValue
= GuidStructureStringToGuidString(Package
.Protocols
[Protocol
])
240 self
._GuidDb
[GuidValue
.upper()] = Protocol
241 for Ppi
in Package
.Ppis
:
242 GuidValue
= GuidStructureStringToGuidString(Package
.Ppis
[Ppi
])
243 self
._GuidDb
[GuidValue
.upper()] = Ppi
244 for Guid
in Package
.Guids
:
245 GuidValue
= GuidStructureStringToGuidString(Package
.Guids
[Guid
])
246 self
._GuidDb
[GuidValue
.upper()] = Guid
249 # Parse the binary dependency expression files.
251 # This function parses the binary dependency expression file and translate it
252 # to the instruction list.
254 # @param self The object pointer
255 # @param DepexFileName The file name of binary dependency expression file.
257 def ParseDepexFile(self
, DepexFileName
):
258 DepexFile
= open(DepexFileName
, "rb")
260 OpCode
= DepexFile
.read(1)
262 Statement
= gOpCodeList
[struct
.unpack("B", OpCode
)[0]]
263 if Statement
in ["BEFORE", "AFTER", "PUSH"]:
264 GuidValue
= "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % \
265 struct
.unpack("=LHHBBBBBBBB", DepexFile
.read(16))
266 GuidString
= self
._GuidDb
.get(GuidValue
, GuidValue
)
267 Statement
= "%s %s" % (Statement
, GuidString
)
268 DepexStatement
.append(Statement
)
269 OpCode
= DepexFile
.read(1)
271 return DepexStatement
274 # Reports library information
276 # This class reports the module library subsection in the build report file.
278 class LibraryReport(object):
280 # Constructor function for class LibraryReport
282 # This constructor function generates LibraryReport object for
285 # @param self The object pointer
286 # @param M Module context information
288 def __init__(self
, M
):
289 self
.LibraryList
= []
290 if int(str(M
.AutoGenVersion
), 0) >= 0x00010005:
291 self
._EdkIIModule
= True
293 self
._EdkIIModule
= False
295 for Lib
in M
.DependentLibraryList
:
296 LibInfPath
= str(Lib
)
297 LibClassList
= Lib
.LibraryClass
[0].LibraryClass
298 LibConstructorList
= Lib
.ConstructorList
299 LibDesstructorList
= Lib
.DestructorList
300 LibDepexList
= Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]
301 self
.LibraryList
.append((LibInfPath
, LibClassList
, LibConstructorList
, LibDesstructorList
, LibDepexList
))
304 # Generate report for module library information
306 # This function generates report for the module library.
307 # If the module is EDKII style one, the additional library class, library
308 # constructor/destructor and dependency expression may also be reported.
310 # @param self The object pointer
311 # @param File The file object for report
313 def GenerateReport(self
, File
):
314 FileWrite(File
, gSubSectionStart
)
315 FileWrite(File
, TAB_BRG_LIBRARY
)
316 if len(self
.LibraryList
) > 0:
317 FileWrite(File
, gSubSectionSep
)
318 for LibraryItem
in self
.LibraryList
:
319 LibInfPath
= LibraryItem
[0]
320 FileWrite(File
, LibInfPath
)
323 # Report library class, library constructor and destructor for
324 # EDKII style module.
326 if self
._EdkIIModule
:
327 LibClass
= LibraryItem
[1]
329 LibConstructor
= " ".join(LibraryItem
[2])
331 EdkIILibInfo
+= " C = " + LibConstructor
332 LibDestructor
= " ".join(LibraryItem
[3])
334 EdkIILibInfo
+= " D = " + LibDestructor
335 LibDepex
= " ".join(LibraryItem
[4])
337 EdkIILibInfo
+= " Depex = " + LibDepex
339 FileWrite(File
, "{%s: %s}" % (LibClass
, EdkIILibInfo
))
341 FileWrite(File
, "{%s}" % LibClass
)
343 FileWrite(File
, gSubSectionEnd
)
346 # Reports dependency expression information
348 # This class reports the module dependency expression subsection in the build report file.
350 class DepexReport(object):
352 # Constructor function for class DepexReport
354 # This constructor function generates DepexReport object for
355 # a module. If the module source contains the DXS file (usually EDK
356 # style module), it uses the dependency in DXS file; otherwise,
357 # it uses the dependency expression from its own INF [Depex] section
358 # and then merges with the ones from its dependent library INF.
360 # @param self The object pointer
361 # @param M Module context information
363 def __init__(self
, M
):
365 self
._DepexFileName
= os
.path
.join(M
.BuildDir
, "OUTPUT", M
.Module
.BaseName
+ ".depex")
366 ModuleType
= M
.ModuleType
368 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
370 if ModuleType
in ["SEC", "PEI_CORE", "DXE_CORE", "SMM_CORE", "UEFI_APPLICATION"]:
373 for Source
in M
.SourceFileList
:
374 if os
.path
.splitext(Source
.Path
)[1].lower() == ".dxs":
375 Match
= gDxsDependencyPattern
.search(open(Source
.Path
).read())
377 self
.Depex
= Match
.group(1).strip()
381 self
.Depex
= M
.DepexExpressionList
.get(M
.ModuleType
, "")
382 self
.ModuleDepex
= " ".join(M
.Module
.DepexExpression
[M
.Arch
, M
.ModuleType
])
383 if not self
.ModuleDepex
:
384 self
.ModuleDepex
= "(None)"
387 for Lib
in M
.DependentLibraryList
:
388 LibDepex
= " ".join(Lib
.DepexExpression
[M
.Arch
, M
.ModuleType
]).strip()
390 LibDepexList
.append("(" + LibDepex
+ ")")
391 self
.LibraryDepex
= " AND ".join(LibDepexList
)
392 if not self
.LibraryDepex
:
393 self
.LibraryDepex
= "(None)"
397 # Generate report for module dependency expression information
399 # This function generates report for the module dependency expression.
401 # @param self The object pointer
402 # @param File The file object for report
403 # @param GlobalDepexParser The platform global Dependency expression parser object
405 def GenerateReport(self
, File
, GlobalDepexParser
):
407 FileWrite(File
, gSubSectionStart
)
408 FileWrite(File
, TAB_DEPEX
)
409 FileWrite(File
, gSubSectionEnd
)
411 FileWrite(File
, gSubSectionStart
)
412 if os
.path
.isfile(self
._DepexFileName
):
414 DepexStatements
= GlobalDepexParser
.ParseDepexFile(self
._DepexFileName
)
415 FileWrite(File
, "Final Dependency Expression (DEPEX) Instructions")
416 for DepexStatement
in DepexStatements
:
417 FileWrite(File
, " %s" % DepexStatement
)
418 FileWrite(File
, gSubSectionSep
)
420 EdkLogger
.warn(None, "Dependency expression file is corrupted", self
._DepexFileName
)
422 FileWrite(File
, "Dependency Expression (DEPEX) from %s" % self
.Source
)
424 if self
.Source
== "INF":
425 FileWrite(File
, "%s" % self
.Depex
, True)
426 FileWrite(File
, gSubSectionSep
)
427 FileWrite(File
, "From Module INF: %s" % self
.ModuleDepex
, True)
428 FileWrite(File
, "From Library INF: %s" % self
.LibraryDepex
, True)
430 FileWrite(File
, "%s" % self
.Depex
)
431 FileWrite(File
, gSubSectionEnd
)
434 # Reports dependency expression information
436 # This class reports the module build flags subsection in the build report file.
438 class BuildFlagsReport(object):
440 # Constructor function for class BuildFlagsReport
442 # This constructor function generates BuildFlagsReport object for
443 # a module. It reports the build tool chain tag and all relevant
444 # build flags to build the module.
446 # @param self The object pointer
447 # @param M Module context information
449 def __init__(self
, M
):
452 # Add build flags according to source file extension so that
453 # irrelevant ones can be filtered out.
455 for Source
in M
.SourceFileList
:
456 Ext
= os
.path
.splitext(Source
.File
)[1].lower()
457 if Ext
in [".c", ".cc", ".cpp"]:
458 BuildOptions
["CC"] = 1
459 elif Ext
in [".s", ".asm"]:
460 BuildOptions
["PP"] = 1
461 BuildOptions
["ASM"] = 1
462 elif Ext
in [".vfr"]:
463 BuildOptions
["VFRPP"] = 1
464 BuildOptions
["VFR"] = 1
465 elif Ext
in [".dxs"]:
466 BuildOptions
["APP"] = 1
467 BuildOptions
["CC"] = 1
468 elif Ext
in [".asl"]:
469 BuildOptions
["ASLPP"] = 1
470 BuildOptions
["ASL"] = 1
471 elif Ext
in [".aslc"]:
472 BuildOptions
["ASLCC"] = 1
473 BuildOptions
["ASLDLINK"] = 1
474 BuildOptions
["CC"] = 1
475 elif Ext
in [".asm16"]:
476 BuildOptions
["ASMLINK"] = 1
477 BuildOptions
["SLINK"] = 1
478 BuildOptions
["DLINK"] = 1
481 # Save module build flags.
483 self
.ToolChainTag
= M
.ToolChain
485 for Tool
in BuildOptions
:
486 self
.BuildFlags
[Tool
+ "_FLAGS"] = M
.BuildOption
.get(Tool
, {}).get("FLAGS", "")
489 # Generate report for module build flags information
491 # This function generates report for the module build flags expression.
493 # @param self The object pointer
494 # @param File The file object for report
496 def GenerateReport(self
, File
):
497 FileWrite(File
, gSubSectionStart
)
498 FileWrite(File
, "Build Flags")
499 FileWrite(File
, "Tool Chain Tag: %s" % self
.ToolChainTag
)
500 for Tool
in self
.BuildFlags
:
501 FileWrite(File
, gSubSectionSep
)
502 FileWrite(File
, "%s = %s" % (Tool
, self
.BuildFlags
[Tool
]), True)
504 FileWrite(File
, gSubSectionEnd
)
508 # Reports individual module information
510 # This class reports the module section in the build report file.
511 # It comprises of module summary, module PCD, library, dependency expression,
512 # build flags sections.
514 class ModuleReport(object):
516 # Constructor function for class ModuleReport
518 # This constructor function generates ModuleReport object for
519 # a separate module in a platform build.
521 # @param self The object pointer
522 # @param M Module context information
523 # @param ReportType The kind of report items in the final report file
525 def __init__(self
, M
, ReportType
):
526 self
.ModuleName
= M
.Module
.BaseName
527 self
.ModuleInfPath
= M
.MetaFile
.File
528 self
.FileGuid
= M
.Guid
530 self
.BuildTimeStamp
= None
533 ModuleType
= M
.ModuleType
535 ModuleType
= gComponentType2ModuleType
.get(M
.ComponentType
, "")
537 # If a module complies to PI 1.1, promote Module type to "SMM_DRIVER"
539 if ModuleType
== "DXE_SMM_DRIVER":
540 PiSpec
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "0x00010000")
541 if int(PiSpec
, 0) >= 0x0001000A:
542 ModuleType
= "SMM_DRIVER"
543 self
.DriverType
= gDriverTypeMap
.get(ModuleType
, "0x2 (FREE_FORM)")
544 self
.UefiSpecVersion
= M
.Module
.Specification
.get("UEFI_SPECIFICATION_VERSION", "")
545 self
.PiSpecVersion
= M
.Module
.Specification
.get("PI_SPECIFICATION_VERSION", "")
546 self
.PciDeviceId
= M
.Module
.Defines
.get("PCI_DEVICE_ID", "")
547 self
.PciVendorId
= M
.Module
.Defines
.get("PCI_VENDOR_ID", "")
548 self
.PciClassCode
= M
.Module
.Defines
.get("PCI_CLASS_CODE", "")
550 self
._BuildDir
= M
.BuildDir
551 self
.ModulePcdSet
= {}
552 if "PCD" in ReportType
:
554 # Collect all module used PCD set: module INF referenced directly or indirectly.
555 # It also saves module INF default values of them in case they exist.
557 for Pcd
in M
.ModulePcdList
+ M
.LibraryPcdList
:
558 self
.ModulePcdSet
.setdefault((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Pcd
.Type
), (Pcd
.InfDefaultValue
, Pcd
.DefaultValue
))
560 self
.LibraryReport
= None
561 if "LIBRARY" in ReportType
:
562 self
.LibraryReport
= LibraryReport(M
)
564 self
.DepexReport
= None
565 if "DEPEX" in ReportType
:
566 self
.DepexReport
= DepexReport(M
)
568 if "BUILD_FLAGS" in ReportType
:
569 self
.BuildFlagsReport
= BuildFlagsReport(M
)
573 # Generate report for module information
575 # This function generates report for separate module expression
576 # in a platform build.
578 # @param self The object pointer
579 # @param File The file object for report
580 # @param GlobalPcdReport The platform global PCD report object
581 # @param GlobalPredictionReport The platform global Prediction report object
582 # @param GlobalDepexParser The platform global Dependency expression parser object
583 # @param ReportType The kind of report items in the final report file
585 def GenerateReport(self
, File
, GlobalPcdReport
, GlobalPredictionReport
, GlobalDepexParser
, ReportType
):
586 FileWrite(File
, gSectionStart
)
588 FwReportFileName
= os
.path
.join(self
._BuildDir
, "DEBUG", self
.ModuleName
+ ".txt")
589 if os
.path
.isfile(FwReportFileName
):
591 FileContents
= open(FwReportFileName
).read()
592 Match
= gModuleSizePattern
.search(FileContents
)
594 self
.Size
= int(Match
.group(1))
596 Match
= gTimeStampPattern
.search(FileContents
)
598 self
.BuildTimeStamp
= datetime
.fromtimestamp(int(Match
.group(1)))
600 EdkLogger
.warn(None, "Fail to read report file", FwReportFileName
)
602 FileWrite(File
, "Module Summary")
603 FileWrite(File
, "Module Name: %s" % self
.ModuleName
)
604 FileWrite(File
, "Module INF Path: %s" % self
.ModuleInfPath
)
605 FileWrite(File
, "File GUID: %s" % self
.FileGuid
)
607 FileWrite(File
, "Size: 0x%X (%.2fK)" % (self
.Size
, self
.Size
/ 1024.0))
608 if self
.BuildTimeStamp
:
609 FileWrite(File
, "Build Time Stamp: %s" % self
.BuildTimeStamp
)
611 FileWrite(File
, "Driver Type: %s" % self
.DriverType
)
612 if self
.UefiSpecVersion
:
613 FileWrite(File
, "UEFI Spec Version: %s" % self
.UefiSpecVersion
)
614 if self
.PiSpecVersion
:
615 FileWrite(File
, "PI Spec Version: %s" % self
.PiSpecVersion
)
617 FileWrite(File
, "PCI Device ID: %s" % self
.PciDeviceId
)
619 FileWrite(File
, "PCI Vendor ID: %s" % self
.PciVendorId
)
620 if self
.PciClassCode
:
621 FileWrite(File
, "PCI Class Code: %s" % self
.PciClassCode
)
623 FileWrite(File
, gSectionSep
)
625 if "PCD" in ReportType
:
626 GlobalPcdReport
.GenerateReport(File
, self
.ModulePcdSet
)
628 if "LIBRARY" in ReportType
:
629 self
.LibraryReport
.GenerateReport(File
)
631 if "DEPEX" in ReportType
:
632 self
.DepexReport
.GenerateReport(File
, GlobalDepexParser
)
634 if "BUILD_FLAGS" in ReportType
:
635 self
.BuildFlagsReport
.GenerateReport(File
)
637 if "FIXED_ADDRESS" in ReportType
and self
.FileGuid
:
638 GlobalPredictionReport
.GenerateReport(File
, self
.FileGuid
)
640 FileWrite(File
, gSectionEnd
)
643 # Reports platform and module PCD information
645 # This class reports the platform PCD section and module PCD subsection
646 # in the build report file.
648 class PcdReport(object):
650 # Constructor function for class PcdReport
652 # This constructor function generates PcdReport object a platform build.
653 # It collects the whole PCD database from platform DSC files, platform
654 # flash description file and package DEC files.
656 # @param self The object pointer
657 # @param Wa Workspace context information
659 def __init__(self
, Wa
):
662 self
.ConditionalPcds
= {}
665 self
.FdfPcdSet
= Wa
.FdfProfile
.PcdDict
669 self
.ModulePcdOverride
= {}
670 for Pa
in Wa
.AutoGenObjectList
:
672 # Collect all platform referenced PCDs and grouped them by PCD token space
675 for Pcd
in Pa
.AllPcdList
:
676 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
677 if Pcd
not in PcdList
:
679 if len(Pcd
.TokenCName
) > self
.MaxLen
:
680 self
.MaxLen
= len(Pcd
.TokenCName
)
682 # Collect the PCD defined in DSC/FDF file, but not used in module
684 UnusedPcdFullList
= []
685 for item
in Pa
.Platform
.Pcds
:
686 Pcd
= Pa
.Platform
.Pcds
[item
]
689 for package
in Pa
.PackageList
:
690 for T
in ["FixedAtBuild", "PatchableInModule", "FeatureFlag", "Dynamic", "DynamicEx"]:
691 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
) in package
.Pcds
:
694 if not Pcd
.DatumType
:
695 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, T
)].DatumType
699 if not Pcd
.DatumType
:
701 # Try to remove Hii and Vpd suffix
702 if PcdType
.startswith("DynamicEx"):
703 PcdType
= "DynamicEx"
704 elif PcdType
.startswith("Dynamic"):
706 for package
in Pa
.PackageList
:
707 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
) in package
.Pcds
:
708 Pcd
.DatumType
= package
.Pcds
[(Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, PcdType
)].DatumType
711 PcdList
= self
.AllPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
712 if Pcd
not in PcdList
and Pcd
not in UnusedPcdFullList
:
713 UnusedPcdFullList
.append(Pcd
)
714 if len(Pcd
.TokenCName
) > self
.MaxLen
:
715 self
.MaxLen
= len(Pcd
.TokenCName
)
717 if GlobalData
.gConditionalPcds
:
718 for PcdItem
in GlobalData
.gConditionalPcds
:
720 (TokenSpaceGuidCName
, TokenCName
) = PcdItem
.split('.')
721 if (TokenCName
, TokenSpaceGuidCName
) in Pa
.Platform
.Pcds
.keys():
722 Pcd
= Pa
.Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)]
723 PcdList
= self
.ConditionalPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
724 if Pcd
not in PcdList
:
728 if UnusedPcdFullList
:
729 for Pcd
in UnusedPcdFullList
:
730 if Pcd
.TokenSpaceGuidCName
+ '.' + Pcd
.TokenCName
in GlobalData
.gConditionalPcds
:
732 UnusedPcdList
.append(Pcd
)
734 for Pcd
in UnusedPcdList
:
735 PcdList
= self
.UnusedPcds
.setdefault(Pcd
.TokenSpaceGuidCName
, {}).setdefault(Pcd
.Type
, [])
736 if Pcd
not in PcdList
:
739 for Module
in Pa
.Platform
.Modules
.values():
741 # Collect module override PCDs
743 for ModulePcd
in Module
.M
.ModulePcdList
+ Module
.M
.LibraryPcdList
:
744 TokenCName
= ModulePcd
.TokenCName
745 TokenSpaceGuid
= ModulePcd
.TokenSpaceGuidCName
746 ModuleDefault
= ModulePcd
.DefaultValue
747 ModulePath
= os
.path
.basename(Module
.M
.MetaFile
.File
)
748 self
.ModulePcdOverride
.setdefault((TokenCName
, TokenSpaceGuid
), {})[ModulePath
] = ModuleDefault
752 # Collect PCD DEC default value.
754 self
.DecPcdDefault
= {}
755 for Pa
in Wa
.AutoGenObjectList
:
756 for Package
in Pa
.PackageList
:
757 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
758 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
759 self
.DecPcdDefault
.setdefault((TokenCName
, TokenSpaceGuidCName
, DecType
), DecDefaultValue
)
761 # Collect PCDs defined in DSC common section
763 self
.DscPcdDefault
= {}
764 for Arch
in Wa
.ArchList
:
765 Platform
= Wa
.BuildDatabase
[Wa
.MetaFile
, Arch
, Wa
.BuildTarget
, Wa
.ToolChain
]
766 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
767 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
769 self
.DscPcdDefault
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
771 def GenerateReport(self
, File
, ModulePcdSet
):
772 if self
.ConditionalPcds
:
773 self
.GenerateReportDetail(File
, ModulePcdSet
, 1)
775 self
.GenerateReportDetail(File
, ModulePcdSet
, 2)
776 self
.GenerateReportDetail(File
, ModulePcdSet
)
779 # Generate report for PCD information
781 # This function generates report for separate module expression
782 # in a platform build.
784 # @param self The object pointer
785 # @param File The file object for report
786 # @param ModulePcdSet Set of all PCDs referenced by module or None for
787 # platform PCD report
788 # @param ReportySubType 0 means platform/module PCD report, 1 means Conditional
789 # directives section report, 2 means Unused Pcds section report
790 # @param DscOverridePcds Module DSC override PCDs set
792 def GenerateReportDetail(self
, File
, ModulePcdSet
, ReportSubType
= 0):
793 PcdDict
= self
.AllPcds
794 if ReportSubType
== 1:
795 PcdDict
= self
.ConditionalPcds
796 elif ReportSubType
== 2:
797 PcdDict
= self
.UnusedPcds
799 if ModulePcdSet
== None:
800 FileWrite(File
, gSectionStart
)
801 if ReportSubType
== 1:
802 FileWrite(File
, "Conditional Directives used by the build system")
803 elif ReportSubType
== 2:
804 FileWrite(File
, "PCDs not used by modules or in conditional directives")
806 FileWrite(File
, "Platform Configuration Database Report")
808 FileWrite(File
, " *B - PCD override in the build option")
809 FileWrite(File
, " *P - Platform scoped PCD override in DSC file")
810 FileWrite(File
, " *F - Platform scoped PCD override in FDF file")
811 if not ReportSubType
:
812 FileWrite(File
, " *M - Module scoped PCD override")
813 FileWrite(File
, gSectionSep
)
815 if not ReportSubType
:
817 # For module PCD sub-section
819 FileWrite(File
, gSubSectionStart
)
820 FileWrite(File
, TAB_BRG_PCD
)
821 FileWrite(File
, gSubSectionSep
)
825 # Group PCD by their token space GUID C Name
828 for Type
in PcdDict
[Key
]:
830 # Group PCD by their usage type
832 TypeName
, DecType
= gPcdTypeMap
.get(Type
, ("", Type
))
833 for Pcd
in PcdDict
[Key
][Type
]:
835 # Get PCD default value and their override relationship
837 DecDefaultValue
= self
.DecPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, DecType
))
838 DscDefaultValue
= self
.DscPcdDefault
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
839 DscDefaultValue
= self
.FdfPcdSet
.get((Pcd
.TokenCName
, Key
), DscDefaultValue
)
840 InfDefaultValue
= None
842 PcdValue
= DecDefaultValue
844 PcdValue
= DscDefaultValue
845 if ModulePcdSet
!= None:
846 if (Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
) not in ModulePcdSet
:
848 InfDefault
, PcdValue
= ModulePcdSet
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
, Type
]
852 BuildOptionMatch
= False
853 if GlobalData
.BuildOptionPcd
:
854 for pcd
in GlobalData
.BuildOptionPcd
:
855 if (Pcd
.TokenSpaceGuidCName
, Pcd
.TokenCName
) == (pcd
[0], pcd
[1]):
857 BuildOptionMatch
= True
861 if ModulePcdSet
== None:
867 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
868 PcdValueNumber
= int(PcdValue
.strip(), 0)
869 if DecDefaultValue
== None:
872 DecDefaultValueNumber
= int(DecDefaultValue
.strip(), 0)
873 DecMatch
= (DecDefaultValueNumber
== PcdValueNumber
)
875 if InfDefaultValue
== None:
878 InfDefaultValueNumber
= int(InfDefaultValue
.strip(), 0)
879 InfMatch
= (InfDefaultValueNumber
== PcdValueNumber
)
881 if DscDefaultValue
== None:
884 DscDefaultValueNumber
= int(DscDefaultValue
.strip(), 0)
885 DscMatch
= (DscDefaultValueNumber
== PcdValueNumber
)
887 if DecDefaultValue
== None:
890 DecMatch
= (DecDefaultValue
.strip() == PcdValue
.strip())
892 if InfDefaultValue
== None:
895 InfMatch
= (InfDefaultValue
.strip() == PcdValue
.strip())
897 if DscDefaultValue
== None:
900 DscMatch
= (DscDefaultValue
.strip() == PcdValue
.strip())
903 # Report PCD item according to their override relationship
906 FileWrite(File
, ' *B %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
907 elif DecMatch
and InfMatch
:
908 FileWrite(File
, ' %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
911 if (Pcd
.TokenCName
, Key
) in self
.FdfPcdSet
:
912 FileWrite(File
, ' *F %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
914 FileWrite(File
, ' *P %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
916 FileWrite(File
, ' *M %-*s: %6s %10s = %-22s' % (self
.MaxLen
, Pcd
.TokenCName
, TypeName
, '(' + Pcd
.DatumType
+ ')', PcdValue
.strip()))
918 if TypeName
in ('DYNHII', 'DEXHII', 'DYNVPD', 'DEXVPD'):
919 for SkuInfo
in Pcd
.SkuInfoList
.values():
920 if TypeName
in ('DYNHII', 'DEXHII'):
921 FileWrite(File
, '%*s: %s: %s' % (self
.MaxLen
+ 4, SkuInfo
.VariableGuid
, SkuInfo
.VariableName
, SkuInfo
.VariableOffset
))
923 FileWrite(File
, '%*s' % (self
.MaxLen
+ 4, SkuInfo
.VpdOffset
))
925 if not DscMatch
and DscDefaultValue
!= None:
926 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DSC DEFAULT', DscDefaultValue
.strip()))
928 if not InfMatch
and InfDefaultValue
!= None:
929 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'INF DEFAULT', InfDefaultValue
.strip()))
931 if not DecMatch
and DecDefaultValue
!= None:
932 FileWrite(File
, ' %*s = %s' % (self
.MaxLen
+ 19, 'DEC DEFAULT', DecDefaultValue
.strip()))
934 if ModulePcdSet
== None:
935 if not BuildOptionMatch
:
936 ModuleOverride
= self
.ModulePcdOverride
.get((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
), {})
937 for ModulePath
in ModuleOverride
:
938 ModuleDefault
= ModuleOverride
[ModulePath
]
939 if Pcd
.DatumType
in ('UINT8', 'UINT16', 'UINT32', 'UINT64'):
940 ModulePcdDefaultValueNumber
= int(ModuleDefault
.strip(), 0)
941 Match
= (ModulePcdDefaultValueNumber
== PcdValueNumber
)
943 Match
= (ModuleDefault
.strip() == PcdValue
.strip())
946 FileWrite(File
, ' *M %-*s = %s' % (self
.MaxLen
+ 19, ModulePath
, ModuleDefault
.strip()))
948 if ModulePcdSet
== None:
949 FileWrite(File
, gSectionEnd
)
951 if not ReportSubType
:
952 FileWrite(File
, gSubSectionEnd
)
957 # Reports platform and module Prediction information
959 # This class reports the platform execution order prediction section and
960 # module load fixed address prediction subsection in the build report file.
962 class PredictionReport(object):
964 # Constructor function for class PredictionReport
966 # This constructor function generates PredictionReport object for the platform.
968 # @param self: The object pointer
969 # @param Wa Workspace context information
971 def __init__(self
, Wa
):
972 self
._MapFileName
= os
.path
.join(Wa
.BuildDir
, Wa
.Name
+ ".map")
973 self
._MapFileParsed
= False
974 self
._EotToolInvoked
= False
975 self
._FvDir
= Wa
.FvDir
976 self
._EotDir
= Wa
.BuildDir
977 self
._FfsEntryPoint
= {}
979 self
._SourceList
= []
980 self
.FixedMapDict
= {}
985 # Collect all platform reference source files and GUID C Name
987 for Pa
in Wa
.AutoGenObjectList
:
988 for Module
in Pa
.LibraryAutoGenList
+ Pa
.ModuleAutoGenList
:
990 # BASE typed modules are EFI agnostic, so we need not scan
991 # their source code to find PPI/Protocol produce or consume
994 if Module
.ModuleType
== "BASE":
997 # Add module referenced source files
999 self
._SourceList
.append(str(Module
))
1001 for Source
in Module
.SourceFileList
:
1002 if os
.path
.splitext(str(Source
))[1].lower() == ".c":
1003 self
._SourceList
.append(" " + str(Source
))
1004 FindIncludeFiles(Source
.Path
, Module
.IncludePathList
, IncludeList
)
1005 for IncludeFile
in IncludeList
.values():
1006 self
._SourceList
.append(" " + IncludeFile
)
1008 for Guid
in Module
.PpiList
:
1009 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.PpiList
[Guid
])
1010 for Guid
in Module
.ProtocolList
:
1011 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.ProtocolList
[Guid
])
1012 for Guid
in Module
.GuidList
:
1013 self
._GuidMap
[Guid
] = GuidStructureStringToGuidString(Module
.GuidList
[Guid
])
1015 if Module
.Guid
and not Module
.IsLibrary
:
1016 EntryPoint
= " ".join(Module
.Module
.ModuleEntryPointList
)
1017 if int(str(Module
.AutoGenVersion
), 0) >= 0x00010005:
1018 RealEntryPoint
= "_ModuleEntryPoint"
1020 RealEntryPoint
= EntryPoint
1021 if EntryPoint
== "_ModuleEntryPoint":
1022 CCFlags
= Module
.BuildOption
.get("CC", {}).get("FLAGS", "")
1023 Match
= gGlueLibEntryPoint
.search(CCFlags
)
1025 EntryPoint
= Match
.group(1)
1027 self
._FfsEntryPoint
[Module
.Guid
.upper()] = (EntryPoint
, RealEntryPoint
)
1031 # Collect platform firmware volume list as the input of EOT.
1035 for Fd
in Wa
.FdfProfile
.FdDict
:
1036 for FdRegion
in Wa
.FdfProfile
.FdDict
[Fd
].RegionList
:
1037 if FdRegion
.RegionType
!= "FV":
1039 for FvName
in FdRegion
.RegionDataList
:
1040 if FvName
in self
._FvList
:
1042 self
._FvList
.append(FvName
)
1043 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1044 for Section
in Ffs
.SectionList
:
1046 for FvSection
in Section
.SectionList
:
1047 if FvSection
.FvName
in self
._FvList
:
1049 self
._FvList
.append(FvSection
.FvName
)
1050 except AttributeError:
1055 # Parse platform fixed address map files
1057 # This function parses the platform final fixed address map file to get
1058 # the database of predicted fixed address for module image base, entry point
1061 # @param self: The object pointer
1063 def _ParseMapFile(self
):
1064 if self
._MapFileParsed
:
1066 self
._MapFileParsed
= True
1067 if os
.path
.isfile(self
._MapFileName
):
1069 FileContents
= open(self
._MapFileName
).read()
1070 for Match
in gMapFileItemPattern
.finditer(FileContents
):
1071 AddressType
= Match
.group(1)
1072 BaseAddress
= Match
.group(2)
1073 EntryPoint
= Match
.group(3)
1074 Guid
= Match
.group(4).upper()
1075 List
= self
.FixedMapDict
.setdefault(Guid
, [])
1076 List
.append((AddressType
, BaseAddress
, "*I"))
1077 List
.append((AddressType
, EntryPoint
, "*E"))
1079 EdkLogger
.warn(None, "Cannot open file to read", self
._MapFileName
)
1082 # Invokes EOT tool to get the predicted the execution order.
1084 # This function invokes EOT tool to calculate the predicted dispatch order
1086 # @param self: The object pointer
1088 def _InvokeEotTool(self
):
1089 if self
._EotToolInvoked
:
1092 self
._EotToolInvoked
= True
1094 for FvName
in self
._FvList
:
1095 FvFile
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv")
1096 if os
.path
.isfile(FvFile
):
1097 FvFileList
.append(FvFile
)
1099 if len(FvFileList
) == 0:
1102 # Write source file list and GUID file list to an intermediate file
1103 # as the input for EOT tool and dispatch List as the output file
1106 SourceList
= os
.path
.join(self
._EotDir
, "SourceFile.txt")
1107 GuidList
= os
.path
.join(self
._EotDir
, "GuidList.txt")
1108 DispatchList
= os
.path
.join(self
._EotDir
, "Dispatch.txt")
1110 TempFile
= open(SourceList
, "w+")
1111 for Item
in self
._SourceList
:
1112 FileWrite(TempFile
, Item
)
1114 TempFile
= open(GuidList
, "w+")
1115 for Key
in self
._GuidMap
:
1116 FileWrite(TempFile
, "%s %s" % (Key
, self
._GuidMap
[Key
]))
1120 from Eot
.Eot
import Eot
1123 # Invoke EOT tool and echo its runtime performance
1125 EotStartTime
= time
.time()
1126 Eot(CommandLineOption
=False, SourceFileList
=SourceList
, GuidList
=GuidList
,
1127 FvFileList
=' '.join(FvFileList
), Dispatch
=DispatchList
, IsInit
=True)
1128 EotEndTime
= time
.time()
1129 EotDuration
= time
.strftime("%H:%M:%S", time
.gmtime(int(round(EotEndTime
- EotStartTime
))))
1130 EdkLogger
.quiet("EOT run time: %s\n" % EotDuration
)
1133 # Parse the output of EOT tool
1135 for Line
in open(DispatchList
):
1136 if len(Line
.split()) < 4:
1138 (Guid
, Phase
, FfsName
, FilePath
) = Line
.split()
1139 Symbol
= self
._FfsEntryPoint
.get(Guid
, [FfsName
, ""])[0]
1140 if len(Symbol
) > self
.MaxLen
:
1141 self
.MaxLen
= len(Symbol
)
1142 self
.ItemList
.append((Phase
, Symbol
, FilePath
))
1144 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1145 EdkLogger
.warn(None, "Failed to generate execution order prediction report, for some error occurred in executing EOT.")
1149 # Generate platform execution order report
1151 # This function generates the predicted module execution order.
1153 # @param self The object pointer
1154 # @param File The file object for report
1156 def _GenerateExecutionOrderReport(self
, File
):
1157 self
._InvokeEotTool
()
1158 if len(self
.ItemList
) == 0:
1160 FileWrite(File
, gSectionStart
)
1161 FileWrite(File
, "Execution Order Prediction")
1162 FileWrite(File
, "*P PEI phase")
1163 FileWrite(File
, "*D DXE phase")
1164 FileWrite(File
, "*E Module INF entry point name")
1165 FileWrite(File
, "*N Module notification function name")
1167 FileWrite(File
, "Type %-*s %s" % (self
.MaxLen
, "Symbol", "Module INF Path"))
1168 FileWrite(File
, gSectionSep
)
1169 for Item
in self
.ItemList
:
1170 FileWrite(File
, "*%sE %-*s %s" % (Item
[0], self
.MaxLen
, Item
[1], Item
[2]))
1172 FileWrite(File
, gSectionStart
)
1175 # Generate Fixed Address report.
1177 # This function generate the predicted fixed address report for a module
1178 # specified by Guid.
1180 # @param self The object pointer
1181 # @param File The file object for report
1182 # @param Guid The module Guid value.
1183 # @param NotifyList The list of all notify function in a module
1185 def _GenerateFixedAddressReport(self
, File
, Guid
, NotifyList
):
1186 self
._ParseMapFile
()
1187 FixedAddressList
= self
.FixedMapDict
.get(Guid
)
1188 if not FixedAddressList
:
1191 FileWrite(File
, gSubSectionStart
)
1192 FileWrite(File
, "Fixed Address Prediction")
1193 FileWrite(File
, "*I Image Loading Address")
1194 FileWrite(File
, "*E Entry Point Address")
1195 FileWrite(File
, "*N Notification Function Address")
1196 FileWrite(File
, "*F Flash Address")
1197 FileWrite(File
, "*M Memory Address")
1198 FileWrite(File
, "*S SMM RAM Offset")
1199 FileWrite(File
, "TOM Top of Memory")
1201 FileWrite(File
, "Type Address Name")
1202 FileWrite(File
, gSubSectionSep
)
1203 for Item
in FixedAddressList
:
1208 Name
= "(Image Base)"
1209 elif Symbol
== "*E":
1210 Name
= self
._FfsEntryPoint
.get(Guid
, ["", "_ModuleEntryPoint"])[1]
1211 elif Symbol
in NotifyList
:
1219 elif "Memory" in Type
:
1225 Value
= "TOM" + Value
1227 FileWrite(File
, "%s %-16s %s" % (Symbol
, Value
, Name
))
1230 # Generate report for the prediction part
1232 # This function generate the predicted fixed address report for a module or
1233 # predicted module execution order for a platform.
1234 # If the input Guid is None, then, it generates the predicted module execution order;
1235 # otherwise it generated the module fixed loading address for the module specified by
1238 # @param self The object pointer
1239 # @param File The file object for report
1240 # @param Guid The module Guid value.
1242 def GenerateReport(self
, File
, Guid
):
1244 self
._GenerateFixedAddressReport
(File
, Guid
.upper(), [])
1246 self
._GenerateExecutionOrderReport
(File
)
1249 # Reports FD region information
1251 # This class reports the FD subsection in the build report file.
1252 # It collects region information of platform flash device.
1253 # If the region is a firmware volume, it lists the set of modules
1254 # and its space information; otherwise, it only lists its region name,
1255 # base address and size in its sub-section header.
1256 # If there are nesting FVs, the nested FVs will list immediate after
1257 # this FD region subsection
1259 class FdRegionReport(object):
1261 # Discover all the nested FV name list.
1263 # This is an internal worker function to discover the all the nested FV information
1264 # in the parent firmware volume. It uses deep first search algorithm recursively to
1265 # find all the FV list name and append them to the list.
1267 # @param self The object pointer
1268 # @param FvName The name of current firmware file system
1269 # @param Wa Workspace context information
1271 def _DiscoverNestedFvList(self
, FvName
, Wa
):
1272 FvDictKey
=FvName
.upper()
1273 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1274 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1275 for Section
in Ffs
.SectionList
:
1277 for FvSection
in Section
.SectionList
:
1278 if FvSection
.FvName
in self
.FvList
:
1280 self
._GuidsDb
[Ffs
.NameGuid
.upper()] = FvSection
.FvName
1281 self
.FvList
.append(FvSection
.FvName
)
1282 self
.FvInfo
[FvSection
.FvName
] = ("Nested FV", 0, 0)
1283 self
._DiscoverNestedFvList
(FvSection
.FvName
, Wa
)
1284 except AttributeError:
1288 # Constructor function for class FdRegionReport
1290 # This constructor function generates FdRegionReport object for a specified FdRegion.
1291 # If the FdRegion is a firmware volume, it will recursively find all its nested Firmware
1292 # volume list. This function also collects GUID map in order to dump module identification
1293 # in the final report.
1295 # @param self: The object pointer
1296 # @param FdRegion The current FdRegion object
1297 # @param Wa Workspace context information
1299 def __init__(self
, FdRegion
, Wa
):
1300 self
.Type
= FdRegion
.RegionType
1301 self
.BaseAddress
= FdRegion
.Offset
1302 self
.Size
= FdRegion
.Size
1306 self
._FvDir
= Wa
.FvDir
1309 # If the input FdRegion is not a firmware volume,
1312 if self
.Type
!= "FV":
1316 # Find all nested FVs in the FdRegion
1318 for FvName
in FdRegion
.RegionDataList
:
1319 if FvName
in self
.FvList
:
1321 self
.FvList
.append(FvName
)
1322 self
.FvInfo
[FvName
] = ("Fd Region", self
.BaseAddress
, self
.Size
)
1323 self
._DiscoverNestedFvList
(FvName
, Wa
)
1327 # Collect PCDs declared in DEC files.
1329 for Pa
in Wa
.AutoGenObjectList
:
1330 for Package
in Pa
.PackageList
:
1331 for (TokenCName
, TokenSpaceGuidCName
, DecType
) in Package
.Pcds
:
1332 DecDefaultValue
= Package
.Pcds
[TokenCName
, TokenSpaceGuidCName
, DecType
].DefaultValue
1333 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DecDefaultValue
1335 # Collect PCDs defined in DSC file
1337 for arch
in Wa
.ArchList
:
1338 Platform
= Wa
.BuildDatabase
[Wa
.MetaFile
, arch
]
1339 for (TokenCName
, TokenSpaceGuidCName
) in Platform
.Pcds
:
1340 DscDefaultValue
= Platform
.Pcds
[(TokenCName
, TokenSpaceGuidCName
)].DefaultValue
1341 PlatformPcds
[(TokenCName
, TokenSpaceGuidCName
)] = DscDefaultValue
1344 # Add PEI and DXE a priori files GUIDs defined in PI specification.
1346 self
._GuidsDb
["1B45CC0A-156A-428A-AF62-49864DA0E6E6"] = "PEI Apriori"
1347 self
._GuidsDb
["FC510EE7-FFDC-11D4-BD41-0080C73C8881"] = "DXE Apriori"
1349 # Add ACPI table storage file
1351 self
._GuidsDb
["7E374E25-8E01-4FEE-87F2-390C23C606CD"] = "ACPI table storage"
1353 for Pa
in Wa
.AutoGenObjectList
:
1354 for ModuleKey
in Pa
.Platform
.Modules
:
1355 M
= Pa
.Platform
.Modules
[ModuleKey
].M
1356 InfPath
= mws
.join(Wa
.WorkspaceDir
, M
.MetaFile
.File
)
1357 self
._GuidsDb
[M
.Guid
.upper()] = "%s (%s)" % (M
.Module
.BaseName
, InfPath
)
1360 # Collect the GUID map in the FV firmware volume
1362 for FvName
in self
.FvList
:
1363 FvDictKey
=FvName
.upper()
1364 if FvDictKey
in Wa
.FdfProfile
.FvDict
:
1365 for Ffs
in Wa
.FdfProfile
.FvDict
[FvName
.upper()].FfsList
:
1368 # collect GUID map for binary EFI file in FDF file.
1370 Guid
= Ffs
.NameGuid
.upper()
1371 Match
= gPcdGuidPattern
.match(Ffs
.NameGuid
)
1373 PcdTokenspace
= Match
.group(1)
1374 PcdToken
= Match
.group(2)
1375 if (PcdToken
, PcdTokenspace
) in PlatformPcds
:
1376 GuidValue
= PlatformPcds
[(PcdToken
, PcdTokenspace
)]
1377 Guid
= GuidStructureByteArrayToGuidString(GuidValue
).upper()
1378 for Section
in Ffs
.SectionList
:
1380 ModuleSectFile
= mws
.join(Wa
.WorkspaceDir
, Section
.SectFileName
)
1381 self
._GuidsDb
[Guid
] = ModuleSectFile
1382 except AttributeError:
1384 except AttributeError:
1389 # Internal worker function to generate report for the FD region
1391 # This internal worker function to generate report for the FD region.
1392 # It the type is firmware volume, it lists offset and module identification.
1394 # @param self The object pointer
1395 # @param File The file object for report
1396 # @param Title The title for the FD subsection
1397 # @param BaseAddress The base address for the FD region
1398 # @param Size The size of the FD region
1399 # @param FvName The FV name if the FD region is a firmware volume
1401 def _GenerateReport(self
, File
, Title
, Type
, BaseAddress
, Size
=0, FvName
=None):
1402 FileWrite(File
, gSubSectionStart
)
1403 FileWrite(File
, Title
)
1404 FileWrite(File
, "Type: %s" % Type
)
1405 FileWrite(File
, "Base Address: 0x%X" % BaseAddress
)
1407 if self
.Type
== "FV":
1411 FvReportFileName
= os
.path
.join(self
._FvDir
, FvName
+ ".Fv.txt")
1414 # Collect size info in the firmware volume.
1416 FvReport
= open(FvReportFileName
).read()
1417 Match
= gFvTotalSizePattern
.search(FvReport
)
1419 FvTotalSize
= int(Match
.group(1), 16)
1420 Match
= gFvTakenSizePattern
.search(FvReport
)
1422 FvTakenSize
= int(Match
.group(1), 16)
1423 FvFreeSize
= FvTotalSize
- FvTakenSize
1425 # Write size information to the report file.
1427 FileWrite(File
, "Size: 0x%X (%.0fK)" % (FvTotalSize
, FvTotalSize
/ 1024.0))
1428 FileWrite(File
, "Fv Name: %s (%.1f%% Full)" % (FvName
, FvTakenSize
* 100.0 / FvTotalSize
))
1429 FileWrite(File
, "Occupied Size: 0x%X (%.0fK)" % (FvTakenSize
, FvTakenSize
/ 1024.0))
1430 FileWrite(File
, "Free Size: 0x%X (%.0fK)" % (FvFreeSize
, FvFreeSize
/ 1024.0))
1431 FileWrite(File
, "Offset Module")
1432 FileWrite(File
, gSubSectionSep
)
1434 # Write module offset and module identification to the report file.
1437 for Match
in gOffsetGuidPattern
.finditer(FvReport
):
1438 Guid
= Match
.group(2).upper()
1439 OffsetInfo
[Match
.group(1)] = self
._GuidsDb
.get(Guid
, Guid
)
1440 OffsetList
= OffsetInfo
.keys()
1442 for Offset
in OffsetList
:
1443 FileWrite (File
, "%s %s" % (Offset
, OffsetInfo
[Offset
]))
1445 EdkLogger
.warn(None, "Fail to read report file", FvReportFileName
)
1447 FileWrite(File
, "Size: 0x%X (%.0fK)" % (Size
, Size
/ 1024.0))
1448 FileWrite(File
, gSubSectionEnd
)
1451 # Generate report for the FD region
1453 # This function generates report for the FD region.
1455 # @param self The object pointer
1456 # @param File The file object for report
1458 def GenerateReport(self
, File
):
1459 if (len(self
.FvList
) > 0):
1460 for FvItem
in self
.FvList
:
1461 Info
= self
.FvInfo
[FvItem
]
1462 self
._GenerateReport
(File
, Info
[0], "FV", Info
[1], Info
[2], FvItem
)
1464 self
._GenerateReport
(File
, "FD Region", self
.Type
, self
.BaseAddress
, self
.Size
)
1467 # Reports FD information
1469 # This class reports the FD section in the build report file.
1470 # It collects flash device information for a platform.
1472 class FdReport(object):
1474 # Constructor function for class FdReport
1476 # This constructor function generates FdReport object for a specified
1479 # @param self The object pointer
1480 # @param Fd The current Firmware device object
1481 # @param Wa Workspace context information
1483 def __init__(self
, Fd
, Wa
):
1484 self
.FdName
= Fd
.FdUiName
1485 self
.BaseAddress
= Fd
.BaseAddress
1487 self
.FdRegionList
= [FdRegionReport(FdRegion
, Wa
) for FdRegion
in Fd
.RegionList
]
1488 self
.FvPath
= os
.path
.join(Wa
.BuildDir
, "FV")
1489 self
.VpdFilePath
= os
.path
.join(self
.FvPath
, "%s.map" % Wa
.Platform
.VpdToolGuid
)
1490 self
.VPDBaseAddress
= 0
1492 self
.VPDInfoList
= []
1493 for index
, FdRegion
in enumerate(Fd
.RegionList
):
1494 if str(FdRegion
.RegionType
) is 'FILE' and Wa
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
1495 self
.VPDBaseAddress
= self
.FdRegionList
[index
].BaseAddress
1496 self
.VPDSize
= self
.FdRegionList
[index
].Size
1499 if os
.path
.isfile(self
.VpdFilePath
):
1500 fd
= open(self
.VpdFilePath
, "r")
1501 Lines
= fd
.readlines()
1504 if len(Line
) == 0 or Line
.startswith("#"):
1507 PcdName
, SkuId
, Offset
, Size
, Value
= Line
.split("#")[0].split("|")
1508 PcdName
, SkuId
, Offset
, Size
, Value
= PcdName
.strip(), SkuId
.strip(), Offset
.strip(), Size
.strip(), Value
.strip()
1509 Offset
= '0x%08X' % (int(Offset
, 16) + self
.VPDBaseAddress
)
1510 self
.VPDInfoList
.append("%s | %s | %s | %s | %s" % (PcdName
, SkuId
, Offset
, Size
, Value
))
1512 EdkLogger
.error("BuildReport", CODE_ERROR
, "Fail to parse VPD information file %s" % self
.VpdFilePath
)
1516 # Generate report for the firmware device.
1518 # This function generates report for the firmware device.
1520 # @param self The object pointer
1521 # @param File The file object for report
1523 def GenerateReport(self
, File
):
1524 FileWrite(File
, gSectionStart
)
1525 FileWrite(File
, "Firmware Device (FD)")
1526 FileWrite(File
, "FD Name: %s" % self
.FdName
)
1527 FileWrite(File
, "Base Address: %s" % self
.BaseAddress
)
1528 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.Size
, self
.Size
/ 1024.0))
1529 if len(self
.FdRegionList
) > 0:
1530 FileWrite(File
, gSectionSep
)
1531 for FdRegionItem
in self
.FdRegionList
:
1532 FdRegionItem
.GenerateReport(File
)
1534 if len(self
.VPDInfoList
) > 0:
1535 FileWrite(File
, gSubSectionStart
)
1536 FileWrite(File
, "FD VPD Region")
1537 FileWrite(File
, "Base Address: 0x%X" % self
.VPDBaseAddress
)
1538 FileWrite(File
, "Size: 0x%X (%.0fK)" % (self
.VPDSize
, self
.VPDSize
/ 1024.0))
1539 FileWrite(File
, gSubSectionSep
)
1540 for item
in self
.VPDInfoList
:
1541 FileWrite(File
, item
)
1542 FileWrite(File
, gSubSectionEnd
)
1543 FileWrite(File
, gSectionEnd
)
1548 # Reports platform information
1550 # This class reports the whole platform information
1552 class PlatformReport(object):
1554 # Constructor function for class PlatformReport
1556 # This constructor function generates PlatformReport object a platform build.
1557 # It generates report for platform summary, flash, global PCDs and detailed
1558 # module information for modules involved in platform build.
1560 # @param self The object pointer
1561 # @param Wa Workspace context information
1562 # @param MaList The list of modules in the platform build
1564 def __init__(self
, Wa
, MaList
, ReportType
):
1565 self
._WorkspaceDir
= Wa
.WorkspaceDir
1566 self
.PlatformName
= Wa
.Name
1567 self
.PlatformDscPath
= Wa
.Platform
1568 self
.Architectures
= " ".join(Wa
.ArchList
)
1569 self
.ToolChain
= Wa
.ToolChain
1570 self
.Target
= Wa
.BuildTarget
1571 self
.OutputPath
= os
.path
.join(Wa
.WorkspaceDir
, Wa
.OutputDir
)
1572 self
.BuildEnvironment
= platform
.platform()
1574 self
.PcdReport
= None
1575 if "PCD" in ReportType
:
1576 self
.PcdReport
= PcdReport(Wa
)
1578 self
.FdReportList
= []
1579 if "FLASH" in ReportType
and Wa
.FdfProfile
and MaList
== None:
1580 for Fd
in Wa
.FdfProfile
.FdDict
:
1581 self
.FdReportList
.append(FdReport(Wa
.FdfProfile
.FdDict
[Fd
], Wa
))
1583 self
.PredictionReport
= None
1584 if "FIXED_ADDRESS" in ReportType
or "EXECUTION_ORDER" in ReportType
:
1585 self
.PredictionReport
= PredictionReport(Wa
)
1587 self
.DepexParser
= None
1588 if "DEPEX" in ReportType
:
1589 self
.DepexParser
= DepexParser(Wa
)
1591 self
.ModuleReportList
= []
1593 self
._IsModuleBuild
= True
1595 self
.ModuleReportList
.append(ModuleReport(Ma
, ReportType
))
1597 self
._IsModuleBuild
= False
1598 for Pa
in Wa
.AutoGenObjectList
:
1599 for ModuleKey
in Pa
.Platform
.Modules
:
1600 self
.ModuleReportList
.append(ModuleReport(Pa
.Platform
.Modules
[ModuleKey
].M
, ReportType
))
1605 # Generate report for the whole platform.
1607 # This function generates report for platform information.
1608 # It comprises of platform summary, global PCD, flash and
1609 # module list sections.
1611 # @param self The object pointer
1612 # @param File The file object for report
1613 # @param BuildDuration The total time to build the modules
1614 # @param ReportType The kind of report items in the final report file
1616 def GenerateReport(self
, File
, BuildDuration
, ReportType
):
1617 FileWrite(File
, "Platform Summary")
1618 FileWrite(File
, "Platform Name: %s" % self
.PlatformName
)
1619 FileWrite(File
, "Platform DSC Path: %s" % self
.PlatformDscPath
)
1620 FileWrite(File
, "Architectures: %s" % self
.Architectures
)
1621 FileWrite(File
, "Tool Chain: %s" % self
.ToolChain
)
1622 FileWrite(File
, "Target: %s" % self
.Target
)
1623 FileWrite(File
, "Output Path: %s" % self
.OutputPath
)
1624 FileWrite(File
, "Build Environment: %s" % self
.BuildEnvironment
)
1625 FileWrite(File
, "Build Duration: %s" % BuildDuration
)
1626 FileWrite(File
, "Report Content: %s" % ", ".join(ReportType
))
1628 if not self
._IsModuleBuild
:
1629 if "PCD" in ReportType
:
1630 self
.PcdReport
.GenerateReport(File
, None)
1632 if "FLASH" in ReportType
:
1633 for FdReportListItem
in self
.FdReportList
:
1634 FdReportListItem
.GenerateReport(File
)
1636 for ModuleReportItem
in self
.ModuleReportList
:
1637 ModuleReportItem
.GenerateReport(File
, self
.PcdReport
, self
.PredictionReport
, self
.DepexParser
, ReportType
)
1639 if not self
._IsModuleBuild
:
1640 if "EXECUTION_ORDER" in ReportType
:
1641 self
.PredictionReport
.GenerateReport(File
, None)
1643 ## BuildReport class
1645 # This base class contain the routines to collect data and then
1646 # applies certain format to the output report
1648 class BuildReport(object):
1650 # Constructor function for class BuildReport
1652 # This constructor function generates BuildReport object a platform build.
1653 # It generates report for platform summary, flash, global PCDs and detailed
1654 # module information for modules involved in platform build.
1656 # @param self The object pointer
1657 # @param ReportFile The file name to save report file
1658 # @param ReportType The kind of report items in the final report file
1660 def __init__(self
, ReportFile
, ReportType
):
1661 self
.ReportFile
= ReportFile
1663 self
.ReportList
= []
1664 self
.ReportType
= []
1666 for ReportTypeItem
in ReportType
:
1667 if ReportTypeItem
not in self
.ReportType
:
1668 self
.ReportType
.append(ReportTypeItem
)
1670 self
.ReportType
= ["PCD", "LIBRARY", "BUILD_FLAGS", "DEPEX", "FLASH", "FIXED_ADDRESS"]
1672 # Adds platform report to the list
1674 # This function adds a platform report to the final report list.
1676 # @param self The object pointer
1677 # @param Wa Workspace context information
1678 # @param MaList The list of modules in the platform build
1680 def AddPlatformReport(self
, Wa
, MaList
=None):
1682 self
.ReportList
.append((Wa
, MaList
))
1685 # Generates the final report.
1687 # This function generates platform build report. It invokes GenerateReport()
1688 # method for every platform report in the list.
1690 # @param self The object pointer
1691 # @param BuildDuration The total time to build the modules
1693 def GenerateReport(self
, BuildDuration
):
1697 for (Wa
, MaList
) in self
.ReportList
:
1698 PlatformReport(Wa
, MaList
, self
.ReportType
).GenerateReport(File
, BuildDuration
, self
.ReportType
)
1699 Content
= FileLinesSplit(File
.getvalue(), gLineMaxLength
)
1700 SaveFileOnChange(self
.ReportFile
, Content
, True)
1701 EdkLogger
.quiet("Build report can be found at %s" % os
.path
.abspath(self
.ReportFile
))
1703 EdkLogger
.error(None, FILE_WRITE_FAILURE
, ExtraData
=self
.ReportFile
)
1705 EdkLogger
.error("BuildReport", CODE_ERROR
, "Unknown fatal error when generating build report", ExtraData
=self
.ReportFile
, RaiseError
=False)
1706 EdkLogger
.quiet("(Python %s on %s\n%s)" % (platform
.python_version(), sys
.platform
, traceback
.format_exc()))
1709 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1710 if __name__
== '__main__':