1## @file
2# This file is used to create report for Eot tool
3#
4# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
5# SPDX-License-Identifier: BSD-2-Clause-Patent
6#
7
8##
9# Import Modules
10#
11from __future__ import absolute_import
12import Common.LongFilePathOs as os
13from . import EotGlobalData
14from Common.LongFilePathSupport import OpenLongFilePath as open
15
16## Report() class
17#
18#  This class defined Report
19#
20#  @param object: Inherited from object class
21#
22class Report(object):
23    ## The constructor
24    #
25    #  @param  self: The object pointer
26    #  @param  ReportName: name of the report
27    #  @param  FvObj: FV object after parsing FV images
28    #
29    def __init__(self, ReportName = 'Report.html', FvObj = None, DispatchName=None):
30        self.ReportName = ReportName
31        self.Op = open(ReportName, 'w+')
32        self.DispatchList = None
33        if DispatchName:
34            self.DispatchList = open(DispatchName, 'w+')
35        self.FvObj = FvObj
36        self.FfsIndex = 0
37        self.PpiIndex = 0
38        self.ProtocolIndex = 0
39        if EotGlobalData.gMACRO['EFI_SOURCE'] == '':
40            EotGlobalData.gMACRO['EFI_SOURCE'] = EotGlobalData.gMACRO['EDK_SOURCE']
41
42    ## WriteLn() method
43    #
44    #  Write a line in the report
45    #
46    #  @param  self: The object pointer
47    #  @param Line:  The lint to be written into
48    #
49    def WriteLn(self, Line):
50        self.Op.write('%s\n' % Line)
51
52    ## GenerateReport() method
53    #
54    #  A caller to generate report
55    #
56    #  @param  self: The object pointer
57    #
58    def GenerateReport(self):
59        self.GenerateHeader()
60        self.GenerateFv()
61        self.GenerateTail()
62        self.Op.close()
63        self.GenerateUnDispatchedList()
64
65    ## GenerateUnDispatchedList() method
66    #
67    #  Create a list for not dispatched items
68    #
69    #  @param  self: The object pointer
70    #
71    def GenerateUnDispatchedList(self):
72        FvObj = self.FvObj
73        EotGlobalData.gOP_UN_DISPATCHED.write('%s\n' % FvObj.Name)
74        for Item in FvObj.UnDispatchedFfsDict.keys():
75            EotGlobalData.gOP_UN_DISPATCHED.write('%s\n' % FvObj.UnDispatchedFfsDict[Item])
76
77    ## GenerateFv() method
78    #
79    #  Generate FV information
80    #
81    #  @param  self: The object pointer
82    #
83    def GenerateFv(self):
84        FvObj = self.FvObj
85        Content = """  <tr>
86    <td width="20%%"><strong>Name</strong></td>
87    <td width="60%%"><strong>Guid</strong></td>
88    <td width="20%%"><strong>Size</strong></td>
89  </tr>"""
90        self.WriteLn(Content)
91
92        for Info in FvObj.BasicInfo:
93            FvName = Info[0]
94            FvGuid = Info[1]
95            FvSize = Info[2]
96
97            Content = """  <tr>
98    <td>%s</td>
99    <td>%s</td>
100    <td>%s</td>
101  </tr>"""  % (FvName, FvGuid, FvSize)
102            self.WriteLn(Content)
103
104        Content = """    <td colspan="3"><table width="100%%"  border="1">
105      <tr>"""
106        self.WriteLn(Content)
107
108        EotGlobalData.gOP_DISPATCH_ORDER.write('Dispatched:\n')
109        for FfsId in FvObj.OrderedFfsDict.keys():
110            self.GenerateFfs(FvObj.OrderedFfsDict[FfsId])
111        Content = """     </table></td>
112  </tr>"""
113        self.WriteLn(Content)
114
115        # For UnDispatched
116        Content = """    <td colspan="3"><table width="100%%"  border="1">
117      <tr>
118        <tr><strong>UnDispatched</strong></tr>"""
119        self.WriteLn(Content)
120
121        EotGlobalData.gOP_DISPATCH_ORDER.write('\nUnDispatched:\n')
122        for FfsId in FvObj.UnDispatchedFfsDict.keys():
123            self.GenerateFfs(FvObj.UnDispatchedFfsDict[FfsId])
124        Content = """     </table></td>
125  </tr>"""
126        self.WriteLn(Content)
127
128    ## GenerateDepex() method
129    #
130    #  Generate Depex information
131    #
132    #  @param  self: The object pointer
133    #  @param DepexString: A DEPEX string needed to be parsed
134    #
135    def GenerateDepex(self, DepexString):
136        NonGuidList = ['AND', 'OR', 'NOT', 'BEFORE', 'AFTER', 'TRUE', 'FALSE']
137        ItemList = DepexString.split(' ')
138        DepexString = ''
139        for Item in ItemList:
140            if Item not in NonGuidList:
141                SqlCommand = """select DISTINCT GuidName from Report where GuidValue like '%s' and ItemMode = 'Produced' group by GuidName""" % (Item)
142                RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
143                if RecordSet != []:
144                    Item = RecordSet[0][0]
145            DepexString = DepexString + Item + ' '
146        Content = """                <tr>
147                  <td width="5%%"></td>
148                  <td width="95%%">%s</td>
149                </tr>""" % (DepexString)
150        self.WriteLn(Content)
151
152    ## GeneratePpi() method
153    #
154    #  Generate PPI information
155    #
156    #  @param self: The object pointer
157    #  @param Name: CName of a GUID
158    #  @param Guid: Value of a GUID
159    #  @param Type: Type of a GUID
160    #
161    def GeneratePpi(self, Name, Guid, Type):
162        self.GeneratePpiProtocol('Ppi', Name, Guid, Type, self.PpiIndex)
163
164    ## GenerateProtocol() method
165    #
166    #  Generate PROTOCOL information
167    #
168    #  @param self: The object pointer
169    #  @param Name: CName of a GUID
170    #  @param Guid: Value of a GUID
171    #  @param Type: Type of a GUID
172    #
173    def GenerateProtocol(self, Name, Guid, Type):
174        self.GeneratePpiProtocol('Protocol', Name, Guid, Type, self.ProtocolIndex)
175
176    ## GeneratePpiProtocol() method
177    #
178    #  Generate PPI/PROTOCOL information
179    #
180    #  @param self: The object pointer
181    #  @param Model: Model of a GUID, PPI or PROTOCOL
182    #  @param Name: Name of a GUID
183    #  @param Guid: Value of a GUID
184    #  @param Type: Type of a GUID
185    #  @param CName: CName(Index) of a GUID
186    #
187    def GeneratePpiProtocol(self, Model, Name, Guid, Type, CName):
188        Content = """                <tr>
189                  <td width="5%%"></td>
190                  <td width="10%%">%s</td>
191                  <td width="85%%" colspan="3">%s</td>
192                  <!-- %s -->
193                </tr>""" % (Model, Name, Guid)
194        self.WriteLn(Content)
195        if Type == 'Produced':
196            SqlCommand = """select DISTINCT SourceFileFullPath, BelongsToFunction from Report where GuidName like '%s' and ItemMode = 'Callback'""" % Name
197            RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
198            for Record in RecordSet:
199                SqlCommand = """select FullPath from File
200                                where ID = (
201                                select DISTINCT BelongsToFile from Inf
202                                where Value1 like '%s')""" % Record[0]
203                ModuleSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
204                Inf = ModuleSet[0][0].replace(EotGlobalData.gMACRO['WORKSPACE'], '.')
205                Function = Record[1]
206                Address = ''
207                for Item in EotGlobalData.gMap:
208                    if Function in EotGlobalData.gMap[Item]:
209                        Address = EotGlobalData.gMap[Item][Function]
210                        break
211                    if '_' + Function in EotGlobalData.gMap[Item]:
212                        Address = EotGlobalData.gMap[Item]['_' + Function]
213                        break
214                Content = """                <tr>
215                      <td width="5%%"></td>
216                      <td width="10%%">%s</td>
217                      <td width="40%%">%s</td>
218                      <td width="35%%">%s</td>
219                      <td width="10%%">%s</td>
220                    </tr>""" % ('Callback', Inf, Function, Address)
221                self.WriteLn(Content)
222
223    ## GenerateFfs() method
224    #
225    #  Generate FFS information
226    #
227    #  @param self: The object pointer
228    #  @param FfsObj: FFS object after FV image is parsed
229    #
230    def GenerateFfs(self, FfsObj):
231        self.FfsIndex = self.FfsIndex + 1
232        if FfsObj is not None and FfsObj.Type in [0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xA]:
233            FfsGuid = FfsObj.Guid
234            FfsOffset = FfsObj._OFF_
235            FfsName = 'Unknown-Module'
236            FfsPath = FfsGuid
237            FfsType = FfsObj._TypeName[FfsObj.Type]
238
239            # Hard code for Binary INF
240            if FfsGuid.upper() == '7BB28B99-61BB-11D5-9A5D-0090273FC14D':
241                FfsName = 'Logo'
242
243            if FfsGuid.upper() == '7E374E25-8E01-4FEE-87F2-390C23C606CD':
244                FfsName = 'AcpiTables'
245
246            if FfsGuid.upper() == '961578FE-B6B7-44C3-AF35-6BC705CD2B1F':
247                FfsName = 'Fat'
248
249            # Find FFS Path and Name
250            SqlCommand = """select Value2 from Inf
251                            where BelongsToFile = (select BelongsToFile from Inf where Value1 = 'FILE_GUID' and lower(Value2) = lower('%s') and Model = %s)
252                            and Model = %s and Value1='BASE_NAME'""" % (FfsGuid, 5001, 5001)
253            RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
254            if RecordSet != []:
255                FfsName = RecordSet[0][0]
256
257            SqlCommand = """select FullPath from File
258                            where ID = (select BelongsToFile from Inf where Value1 = 'FILE_GUID' and lower(Value2) = lower('%s') and Model = %s)
259                            and Model = %s""" % (FfsGuid, 5001, 1011)
260            RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
261            if RecordSet != []:
262                FfsPath = RecordSet[0][0]
263
264            Content = """  <tr>
265      <tr class='styleFfs' id='FfsHeader%s'>
266        <td width="55%%"><span onclick="Display('FfsHeader%s', 'Ffs%s')" onMouseOver="funOnMouseOver()" onMouseOut="funOnMouseOut()">%s</span></td>
267        <td width="15%%">%s</td>
268        <!--<td width="20%%">%s</td>-->
269        <!--<td width="20%%">%s</td>-->
270        <td width="10%%">%s</td>
271      </tr>
272      <tr id='Ffs%s' style='display:none;'>
273        <td colspan="4"><table width="100%%"  border="1">""" % (self.FfsIndex, self.FfsIndex, self.FfsIndex, FfsPath, FfsName, FfsGuid, FfsOffset, FfsType, self.FfsIndex)
274
275            if self.DispatchList:
276                if FfsObj.Type in [0x04, 0x06]:
277                    self.DispatchList.write("%s %s %s %s\n" % (FfsGuid, "P", FfsName, FfsPath))
278                if FfsObj.Type in [0x05, 0x07, 0x08, 0x0A]:
279                    self.DispatchList.write("%s %s %s %s\n" % (FfsGuid, "D", FfsName, FfsPath))
280
281            self.WriteLn(Content)
282
283            EotGlobalData.gOP_DISPATCH_ORDER.write('%s\n' %FfsName)
284
285            if FfsObj.Depex != '':
286                Content = """          <tr>
287            <td><span id='DepexHeader%s' class="styleDepex" onclick="Display('DepexHeader%s', 'Depex%s')" onMouseOver="funOnMouseOver()" onMouseOut="funOnMouseOut()">&nbsp&nbspDEPEX expression</span></td>
288          </tr>
289          <tr id='Depex%s' style='display:none;'>
290            <td><table width="100%%"  border="1">""" % (self.FfsIndex, self.FfsIndex, self.FfsIndex, self.FfsIndex)
291                self.WriteLn(Content)
292                self.GenerateDepex(FfsObj.Depex)
293                Content = """            </table></td>
294          </tr>"""
295                self.WriteLn(Content)
296            # End of DEPEX
297
298            # Find Consumed Ppi/Protocol
299            SqlCommand = """select ModuleName, ItemType, GuidName, GuidValue, GuidMacro from Report
300                            where SourceFileFullPath in
301                            (select Value1 from Inf where BelongsToFile =
302                            (select BelongsToFile from Inf
303                            where Value1 = 'FILE_GUID' and Value2 like '%s' and Model = %s)
304                            and Model = %s)
305                            and ItemMode = 'Consumed' group by GuidName order by ItemType""" \
306                            % (FfsGuid, 5001, 3007)
307
308            RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
309            if RecordSet != []:
310                Count = len(RecordSet)
311                Content = """          <tr>
312            <td><span id='ConsumedHeader%s' class="styleConsumed" onclick="Display('ConsumedHeader%s', 'Consumed%s')" onMouseOver="funOnMouseOver()" onMouseOut="funOnMouseOut()">&nbsp&nbspConsumed Ppis/Protocols List (%s)</span></td>
313          </tr>
314          <tr id='Consumed%s' style='display:none;'>
315            <td><table width="100%%"  border="1">""" % (self.FfsIndex, self.FfsIndex, self.FfsIndex, Count, self.FfsIndex)
316                self.WriteLn(Content)
317                self.ProtocolIndex = 0
318                for Record in RecordSet:
319                    self.ProtocolIndex = self.ProtocolIndex + 1
320                    Name = Record[2]
321                    CName = Record[4]
322                    Guid = Record[3]
323                    Type = Record[1]
324                    self.GeneratePpiProtocol(Type, Name, Guid, 'Consumed', CName)
325
326                Content = """            </table></td>
327          </tr>"""
328                self.WriteLn(Content)
329            #End of Consumed Ppi/Protocol
330
331            # Find Produced Ppi/Protocol
332            SqlCommand = """select ModuleName, ItemType, GuidName, GuidValue, GuidMacro from Report
333                            where SourceFileFullPath in
334                            (select Value1 from Inf where BelongsToFile =
335                            (select BelongsToFile from Inf
336                            where Value1 = 'FILE_GUID' and Value2 like '%s' and Model = %s)
337                            and Model = %s)
338                            and ItemMode = 'Produced' group by GuidName order by ItemType""" \
339                            % (FfsGuid, 5001, 3007)
340
341            RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand)
342            if RecordSet != []:
343                Count = len(RecordSet)
344                Content = """          <tr>
345            <td><span id='ProducedHeader%s' class="styleProduced" onclick="Display('ProducedHeader%s', 'Produced%s')" onMouseOver="funOnMouseOver()" onMouseOut="funOnMouseOut()">&nbsp&nbspProduced Ppis/Protocols List (%s)</span></td>
346          </tr>
347          <tr id='Produced%s' style='display:none;'>
348            <td><table width="100%%"  border="1">""" % (self.FfsIndex, self.FfsIndex, self.FfsIndex, Count, self.FfsIndex)
349                self.WriteLn(Content)
350                self.PpiIndex = 0
351                for Record in RecordSet:
352                    self.PpiIndex = self.PpiIndex + 1
353                    Name = Record[2]
354                    CName = Record[4]
355                    Guid = Record[3]
356                    Type = Record[1]
357                    self.GeneratePpiProtocol(Type, Name, Guid, 'Produced', CName)
358
359                Content = """            </table></td>
360          </tr>"""
361                self.WriteLn(Content)
362            RecordSet = None
363            # End of Produced Ppi/Protocol
364
365            Content = """        </table></td>
366        </tr>"""
367            self.WriteLn(Content)
368
369    ## GenerateTail() method
370    #
371    #  Generate end tags of HTML report
372    #
373    #  @param self: The object pointer
374    #
375    def GenerateTail(self):
376        Tail = """</table>
377</body>
378</html>"""
379        self.WriteLn(Tail)
380
381    ## GenerateHeader() method
382    #
383    #  Generate start tags of HTML report
384    #
385    #  @param self: The object pointer
386    #
387    def GenerateHeader(self):
388        Header = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
389"http://www.w3.org/TR/html4/loose.dtd">
390<html>
391<head>
392<title>Execution Order Tool Report</title>
393<meta http-equiv="Content-Type" content="text/html">
394<style type="text/css">
395<!--
396.styleFfs {
397    color: #006600;
398    font-weight: bold;
399}
400.styleDepex {
401    color: #FF0066;
402    font-weight: bold;
403}
404.styleProduced {
405    color: #0000FF;
406    font-weight: bold;
407}
408.styleConsumed {
409    color: #FF00FF;
410    font-weight: bold;
411}
412-->
413</style>
414<Script type="text/javascript">
415function Display(ParentID, SubID)
416{
417    SubItem = document.getElementById(SubID);
418    ParentItem = document.getElementById(ParentID);
419    if (SubItem.style.display == 'none')
420    {
421        SubItem.style.display = ''
422        ParentItem.style.fontWeight = 'normal'
423    }
424    else
425    {
426        SubItem.style.display = 'none'
427        ParentItem.style.fontWeight = 'bold'
428    }
429
430}
431
432function funOnMouseOver()
433{
434    document.body.style.cursor = "hand";
435}
436
437function funOnMouseOut()
438{
439    document.body.style.cursor = "";
440}
441
442</Script>
443</head>
444
445<body>
446<table width="100%%"  border="1">"""
447        self.WriteLn(Header)
448
449##
450#
451# This acts like the main() function for the script, unless it is 'import'ed into another
452# script.
453#
454if __name__ == '__main__':
455    # Initialize log system
456    FilePath = 'FVRECOVERYFLOPPY.fv'
457    if FilePath.lower().endswith(".fv"):
458        fd = open(FilePath, 'rb')
459        buf = array('B')
460        try:
461            buf.fromfile(fd, os.path.getsize(FilePath))
462        except EOFError:
463            pass
464
465        fv = FirmwareVolume("FVRECOVERY", buf, 0)
466
467    report = Report('Report.html', fv)
468    report.GenerateReport()
469