Sync EDKII BaseTools to BaseTools project r1903.
[efi/edk2/.git] / edk2 / BaseTools / Source / Python / Eot / FvImage.py
1 ## @file
2 # Parse FV image
3 #
4 # Copyright (c) 2008 - 2010, Intel Corporation
5 # All rights reserved. This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution.  The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
9 #
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 #
13
14 ## Import Modules
15 #
16 import os
17 import re
18 import sys
19 import uuid
20 import struct
21 import codecs
22 import copy
23
24 from UserDict import IterableUserDict
25 from cStringIO import StringIO
26 from array import array
27
28 from CommonDataClass import *
29 from Common.Misc import sdict, GuidStructureStringToGuidString
30
31 import Common.EdkLogger as EdkLogger
32
33 import EotGlobalData
34
35 # Global definiton
36 gFfsPrintTitle  = "%-36s  %-21s %8s %8s %8s  %-4s %-36s" % ("GUID", "TYPE", "OFFSET", "SIZE", "FREE", "ALIGN", "NAME")
37 gFfsPrintFormat = "%36s  %-21s %8X %8X %8X  %4s %-36s"
38 gGuidStringFormat = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"
39 gPeiAprioriFileNameGuid = '1b45cc0a-156a-428a-af62-49864da0e6e6'
40 gAprioriGuid = 'fc510ee7-ffdc-11d4-bd41-0080c73c8881'
41 gIndention = -4
42
43 ## Image() class
44 #
45 #  A class for Image
46 #
47 class Image(array):
48     _HEADER_ = struct.Struct("")
49     _HEADER_SIZE_ = _HEADER_.size
50
51     def __new__(cls, *args, **kwargs):
52         return array.__new__(cls, 'B')
53
54     def __init__(m, ID=None):
55         if ID == None:
56             m._ID_ = str(uuid.uuid1()).upper()
57         else:
58             m._ID_ = ID
59         m._BUF_ = None
60         m._LEN_ = None
61         m._OFF_ = None
62
63         m._SubImages = sdict() # {offset: Image()}
64
65         array.__init__(m, 'B')
66
67     def __repr__(m):
68         return m._ID_
69
70     def __len__(m):
71         Len = array.__len__(m)
72         for Offset in m._SubImages:
73             Len += len(m._SubImages[Offset])
74         return Len
75
76     def _Unpack(m):
77         m.extend(m._BUF_[m._OFF_ : m._OFF_ + m._LEN_])
78         return len(m)
79
80     def _Pack(m, PadByte=0xFF):
81         raise NotImplementedError
82
83     def frombuffer(m, Buffer, Offset=0, Size=None):
84         m._BUF_ = Buffer
85         m._OFF_ = Offset
86         # we may need the Size information in advance if it's given
87         m._LEN_ = Size
88         m._LEN_ = m._Unpack()
89
90     def empty(m):
91         del m[0:]
92
93     def GetField(m, FieldStruct, Offset=0):
94         return FieldStruct.unpack_from(m, Offset)
95
96     def SetField(m, FieldStruct, Offset, *args):
97         # check if there's enough space
98         Size = FieldStruct.size
99         if Size > len(m):
100             m.extend([0] * (Size - len(m)))
101         FieldStruct.pack_into(m, Offset, *args)
102
103     def _SetData(m, Data):
104         if len(m) < m._HEADER_SIZE_:
105             m.extend([0] * (m._HEADER_SIZE_ - len(m)))
106         else:
107             del m[m._HEADER_SIZE_:]
108         m.extend(Data)
109
110     def _GetData(m):
111         if len(m) > m._HEADER_SIZE_:
112             return m[m._HEADER_SIZE_:]
113         return None
114
115     Data = property(_GetData, _SetData)
116
117 ## FirmwareVolume() class
118 #
119 #  A class for Firmware Volume
120 #
121 class FirmwareVolume(Image):
122     # Read FvLength, Attributes, HeaderLength, Checksum
123     _HEADER_ = struct.Struct("16x 1I2H8B 1Q 4x 1I 1H 1H")
124     _HEADER_SIZE_ = _HEADER_.size
125
126     _FfsGuid = "8C8CE578-8A3D-4F1C-9935-896185C32DD3"
127
128     _GUID_      = struct.Struct("16x 1I2H8B")
129     _LENGTH_    = struct.Struct("16x 16x 1Q")
130     _SIG_       = struct.Struct("16x 16x 8x 1I")
131     _ATTR_      = struct.Struct("16x 16x 8x 4x 1I")
132     _HLEN_      = struct.Struct("16x 16x 8x 4x 4x 1H")
133     _CHECKSUM_  = struct.Struct("16x 16x 8x 4x 4x 2x 1H")
134
135     def __init__(self, Name=''):
136         Image.__init__(self)
137         self.Name = Name
138         self.FfsDict = sdict()
139         self.OrderedFfsDict = sdict()
140         self.UnDispatchedFfsDict = sdict()
141         self.NoDepexFfsDict = sdict()
142         self.ProtocolList = sdict()
143
144     def CheckArchProtocol(self):
145         for Item in EotGlobalData.gArchProtocolGuids:
146             if Item.lower() not in EotGlobalData.gProtocolList:
147
148                 return False
149
150         return True
151
152     def ParseDepex(self, Depex, Type):
153         List = None
154         if Type == 'Ppi':
155             List = EotGlobalData.gPpiList
156         if Type == 'Protocol':
157             List = EotGlobalData.gProtocolList
158         DepexStack = []
159         DepexList = []
160         DepexString = ''
161         FileDepex = None
162         CouldBeLoaded = True
163         for Index in range(0, len(Depex.Expression)):
164             Item = Depex.Expression[Index]
165             if Item == 0x00:
166                 Index = Index + 1
167                 Guid = gGuidStringFormat % Depex.Expression[Index]
168                 if Guid in self.OrderedFfsDict and Depex.Expression[Index + 1] == 0x08:
169                     return (True, 'BEFORE %s' % Guid, [Guid, 'BEFORE'])
170             elif Item == 0x01:
171                 Index = Index + 1
172                 Guid = gGuidStringFormat % Depex.Expression[Index]
173                 if Guid in self.OrderedFfsDict and Depex.Expression[Index + 1] == 0x08:
174                     return (True, 'AFTER %s' % Guid, [Guid, 'AFTER'])
175             elif Item == 0x02:
176                 Index = Index + 1
177                 Guid = gGuidStringFormat % Depex.Expression[Index]
178                 if Guid.lower() in List:
179                     DepexStack.append(True)
180                     DepexList.append(Guid)
181                 else:
182                     DepexStack.append(False)
183                     DepexList.append(Guid)
184                 continue
185             elif Item == 0x03 or Item == 0x04:
186                 DepexStack.append(eval(str(DepexStack.pop()) + ' ' + Depex._OPCODE_STRING_[Item].lower() + ' ' + str(DepexStack.pop())))
187                 DepexList.append(str(DepexList.pop()) + ' ' + Depex._OPCODE_STRING_[Item].upper() + ' ' + str(DepexList.pop()))
188             elif Item == 0x05:
189                 DepexStack.append(eval(Depex._OPCODE_STRING_[Item].lower() + ' ' + str(DepexStack.pop())))
190                 DepexList.append(Depex._OPCODE_STRING_[Item].lower() + ' ' + str(DepexList.pop()))
191             elif Item == 0x06:
192                 DepexStack.append(True)
193                 DepexList.append('TRUE')
194                 DepexString = DepexString + 'TRUE' + ' '
195             elif Item == 0x07:
196                 DepexStack.append(False)
197                 DepexList.append('False')
198                 DepexString = DepexString + 'FALSE' + ' '
199             elif Item == 0x08:
200                 if Index != len(Depex.Expression) - 1:
201                     CouldBeLoaded = False
202                 else:
203                     CouldBeLoaded = DepexStack.pop()
204             else:
205                 CouldBeLoaded = False
206         if DepexList != []:
207             DepexString = DepexList[0].strip()
208         return (CouldBeLoaded, DepexString, FileDepex)
209
210     def Dispatch(self, Db = None):
211         if Db == None:
212             return False
213         self.UnDispatchedFfsDict = copy.copy(self.FfsDict)
214         # Find PeiCore, DexCore, PeiPriori, DxePriori first
215         FfsSecCoreGuid = None
216         FfsPeiCoreGuid = None
217         FfsDxeCoreGuid = None
218         FfsPeiPrioriGuid = None
219         FfsDxePrioriGuid = None
220         for FfsID in self.UnDispatchedFfsDict:
221             Ffs = self.UnDispatchedFfsDict[FfsID]
222             if Ffs.Type == 0x03:
223                 FfsSecCoreGuid = FfsID
224                 continue
225             if Ffs.Type == 0x04:
226                 FfsPeiCoreGuid = FfsID
227                 continue
228             if Ffs.Type == 0x05:
229                 FfsDxeCoreGuid = FfsID
230                 continue
231             if Ffs.Guid.lower() == gPeiAprioriFileNameGuid:
232                 FfsPeiPrioriGuid = FfsID
233                 continue
234             if Ffs.Guid.lower() == gAprioriGuid:
235                 FfsDxePrioriGuid = FfsID
236                 continue
237
238         # Parse SEC_CORE first
239         if FfsSecCoreGuid != None:
240             self.OrderedFfsDict[FfsSecCoreGuid] = self.UnDispatchedFfsDict.pop(FfsSecCoreGuid)
241             self.LoadPpi(Db, FfsSecCoreGuid)
242
243         # Parse PEI first
244         if FfsPeiCoreGuid != None:
245             self.OrderedFfsDict[FfsPeiCoreGuid] = self.UnDispatchedFfsDict.pop(FfsPeiCoreGuid)
246             self.LoadPpi(Db, FfsPeiCoreGuid)
247             if FfsPeiPrioriGuid != None:
248                 # Load PEIM described in priori file
249                 FfsPeiPriori = self.UnDispatchedFfsDict.pop(FfsPeiPrioriGuid)
250                 if len(FfsPeiPriori.Sections) == 1:
251                     Section = FfsPeiPriori.Sections.popitem()[1]
252                     if Section.Type == 0x19:
253                         GuidStruct = struct.Struct('1I2H8B')
254                         Start = 4
255                         while len(Section) > Start:
256                             Guid = GuidStruct.unpack_from(Section[Start : Start + 16])
257                             GuidString = gGuidStringFormat % Guid
258                             Start = Start + 16
259                             if GuidString in self.UnDispatchedFfsDict:
260                                 self.OrderedFfsDict[GuidString] = self.UnDispatchedFfsDict.pop(GuidString)
261                                 self.LoadPpi(Db, GuidString)
262
263         self.DisPatchPei(Db)
264
265         # Parse DXE then
266         if FfsDxeCoreGuid != None:
267             self.OrderedFfsDict[FfsDxeCoreGuid] = self.UnDispatchedFfsDict.pop(FfsDxeCoreGuid)
268             self.LoadProtocol(Db, FfsDxeCoreGuid)
269             if FfsDxePrioriGuid != None:
270                 # Load PEIM described in priori file
271                 FfsDxePriori = self.UnDispatchedFfsDict.pop(FfsDxePrioriGuid)
272                 if len(FfsDxePriori.Sections) == 1:
273                     Section = FfsDxePriori.Sections.popitem()[1]
274                     if Section.Type == 0x19:
275                         GuidStruct = struct.Struct('1I2H8B')
276                         Start = 4
277                         while len(Section) > Start:
278                             Guid = GuidStruct.unpack_from(Section[Start : Start + 16])
279                             GuidString = gGuidStringFormat % Guid
280                             Start = Start + 16
281                             if GuidString in self.UnDispatchedFfsDict:
282                                 self.OrderedFfsDict[GuidString] = self.UnDispatchedFfsDict.pop(GuidString)
283                                 self.LoadProtocol(Db, GuidString)
284
285         self.DisPatchDxe(Db)
286
287     def DisPatchNoDepexFfs(self, Db):
288         # Last Load Drivers without Depex
289         for FfsID in self.NoDepexFfsDict:
290             NewFfs = self.NoDepexFfsDict.pop(FfsID)
291             self.OrderedFfsDict[FfsID] = NewFfs
292             self.LoadProtocol(Db, FfsID)
293
294         return True
295
296     def LoadCallbackProtocol(self):
297         IsLoad = True
298         for Protocol in self.ProtocolList:
299             for Callback in self.ProtocolList[Protocol][1]:
300                 if Callback[0] not in self.OrderedFfsDict.keys():
301                     IsLoad = False
302                     continue
303             if IsLoad:
304                 EotGlobalData.gProtocolList[Protocol.lower()] = self.ProtocolList[Protocol][0]
305                 self.ProtocolList.pop(Protocol)
306
307     def LoadProtocol(self, Db, ModuleGuid):
308         SqlCommand = """select GuidValue from Report
309                         where SourceFileFullPath in
310                         (select Value1 from Inf where BelongsToFile =
311                         (select BelongsToFile from Inf
312                         where Value1 = 'FILE_GUID' and Value2 like '%s' and Model = %s)
313                         and Model = %s)
314                         and ItemType = 'Protocol' and ItemMode = 'Produced'""" \
315                         % (ModuleGuid, 5001, 3007)
316         RecordSet = Db.TblReport.Exec(SqlCommand)
317         for Record in RecordSet:
318             SqlCommand = """select Value2 from Inf where BelongsToFile =
319                             (select DISTINCT BelongsToFile from Inf
320                             where Value1 =
321                             (select SourceFileFullPath from Report
322                             where GuidValue like '%s' and ItemMode = 'Callback'))
323                             and Value1 = 'FILE_GUID'""" % Record[0]
324             CallBackSet = Db.TblReport.Exec(SqlCommand)
325             if CallBackSet != []:
326                 EotGlobalData.gProtocolList[Record[0].lower()] = ModuleGuid
327             else:
328                 EotGlobalData.gProtocolList[Record[0].lower()] = ModuleGuid
329
330     def LoadPpi(self, Db, ModuleGuid):
331         SqlCommand = """select GuidValue from Report
332                         where SourceFileFullPath in
333                         (select Value1 from Inf where BelongsToFile =
334                         (select BelongsToFile from Inf
335                         where Value1 = 'FILE_GUID' and Value2 like '%s' and Model = %s)
336                         and Model = %s)
337                         and ItemType = 'Ppi' and ItemMode = 'Produced'""" \
338                         % (ModuleGuid, 5001, 3007)
339         RecordSet = Db.TblReport.Exec(SqlCommand)
340         for Record in RecordSet:
341             EotGlobalData.gPpiList[Record[0].lower()] = ModuleGuid
342
343     def DisPatchDxe(self, Db):
344         IsInstalled = False
345         ScheduleList = sdict()
346         for FfsID in self.UnDispatchedFfsDict:
347             CouldBeLoaded = False
348             DepexString = ''
349             FileDepex = None
350             Ffs = self.UnDispatchedFfsDict[FfsID]
351             if Ffs.Type == 0x07:
352                 # Get Depex
353                 IsFoundDepex = False
354                 for Section in Ffs.Sections.values():
355                     # Find Depex
356                     if Section.Type == 0x13:
357                         IsFoundDepex = True
358                         CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(Section._SubImages[4], 'Protocol')
359                         break
360                     if Section.Type == 0x01:
361                         CompressSections = Section._SubImages[4]
362                         for CompressSection in CompressSections.Sections:
363                             if CompressSection.Type == 0x13:
364                                 IsFoundDepex = True
365                                 CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(CompressSection._SubImages[4], 'Protocol')
366                                 break
367                             if CompressSection.Type == 0x02:
368                                 NewSections = CompressSection._SubImages[4]
369                                 for NewSection in NewSections.Sections:
370                                     if NewSection.Type == 0x13:
371                                         IsFoundDepex = True
372                                         CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(NewSection._SubImages[4], 'Protocol')
373                                         break
374
375                 # Not find Depex
376                 if not IsFoundDepex:
377                     CouldBeLoaded = self.CheckArchProtocol()
378                     DepexString = ''
379                     FileDepex = None
380
381                 # Append New Ffs
382                 if CouldBeLoaded:
383                     IsInstalled = True
384                     NewFfs = self.UnDispatchedFfsDict.pop(FfsID)
385                     NewFfs.Depex = DepexString
386                     if FileDepex != None:
387                         ScheduleList.insert.insert(FileDepex[1], FfsID, NewFfs, FileDepex[0])
388                     else:
389                         ScheduleList[FfsID] = NewFfs
390                 else:
391                     self.UnDispatchedFfsDict[FfsID].Depex = DepexString
392
393         for FfsID in ScheduleList:
394             NewFfs = ScheduleList.pop(FfsID)
395             FfsName = 'UnKnown'
396             self.OrderedFfsDict[FfsID] = NewFfs
397             self.LoadProtocol(Db, FfsID)
398
399             SqlCommand = """select Value2 from Inf
400                             where BelongsToFile = (select BelongsToFile from Inf where Value1 = 'FILE_GUID' and lower(Value2) = lower('%s') and Model = %s)
401                             and Model = %s and Value1='BASE_NAME'""" % (FfsID, 5001, 5001)
402             RecordSet = Db.TblReport.Exec(SqlCommand)
403             if RecordSet != []:
404                 FfsName = RecordSet[0][0]
405
406         if IsInstalled:
407             self.DisPatchDxe(Db)
408
409     def DisPatchPei(self, Db):
410         IsInstalled = False
411         for FfsID in self.UnDispatchedFfsDict:
412             CouldBeLoaded = True
413             DepexString = ''
414             FileDepex = None
415             Ffs = self.UnDispatchedFfsDict[FfsID]
416             if Ffs.Type == 0x06 or Ffs.Type == 0x08:
417                 # Get Depex
418                 for Section in Ffs.Sections.values():
419                     if Section.Type == 0x1B:
420                         CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(Section._SubImages[4], 'Ppi')
421                         break
422
423                     if Section.Type == 0x01:
424                         CompressSections = Section._SubImages[4]
425                         for CompressSection in CompressSections.Sections:
426                             if CompressSection.Type == 0x1B:
427                                 CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(CompressSection._SubImages[4], 'Ppi')
428                                 break
429                             if CompressSection.Type == 0x02:
430                                 NewSections = CompressSection._SubImages[4]
431                                 for NewSection in NewSections.Sections:
432                                     if NewSection.Type == 0x1B:
433                                         CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(NewSection._SubImages[4], 'Ppi')
434                                         break
435
436                 # Append New Ffs
437                 if CouldBeLoaded:
438                     IsInstalled = True
439                     NewFfs = self.UnDispatchedFfsDict.pop(FfsID)
440                     NewFfs.Depex = DepexString
441                     self.OrderedFfsDict[FfsID] = NewFfs
442                     self.LoadPpi(Db, FfsID)
443                 else:
444                     self.UnDispatchedFfsDict[FfsID].Depex = DepexString
445
446         if IsInstalled:
447             self.DisPatchPei(Db)
448
449
450     def __str__(self):
451         global gIndention
452         gIndention += 4
453         FvInfo = '\n' + ' ' * gIndention
454         FvInfo +=  "[FV:%s] file_system=%s size=%x checksum=%s\n" % (self.Name, self.FileSystemGuid, self.Size, self.Checksum)
455         FfsInfo = "\n".join([str(self.FfsDict[FfsId]) for FfsId in self.FfsDict])
456         gIndention -= 4
457         return FvInfo + FfsInfo
458
459     def _Unpack(self):
460         Size = self._LENGTH_.unpack_from(self._BUF_, self._OFF_)[0]
461         self.empty()
462         self.extend(self._BUF_[self._OFF_:self._OFF_+Size])
463
464         # traverse the FFS
465         EndOfFv = Size
466         FfsStartAddress = self.HeaderSize
467         LastFfsObj = None
468         while FfsStartAddress < EndOfFv:
469             FfsObj = Ffs()
470             FfsObj.frombuffer(self, FfsStartAddress)
471             FfsId = repr(FfsObj)
472             if ((self.Attributes & 0x00000800) != 0 and len(FfsObj) == 0xFFFFFF) \
473                 or ((self.Attributes & 0x00000800) == 0 and len(FfsObj) == 0):
474                 if LastFfsObj != None:
475                     LastFfsObj.FreeSpace = EndOfFv - LastFfsObj._OFF_ - len(LastFfsObj)
476             else:
477                 if FfsId in self.FfsDict:
478                     EdkLogger.error("FV", 0, "Duplicate GUID in FFS",
479                                     ExtraData="\t%s @ %s\n\t%s @ %s" \
480                                     % (FfsObj.Guid, FfsObj.Offset,
481                                        self.FfsDict[FfsId].Guid, self.FfsDict[FfsId].Offset))
482                 self.FfsDict[FfsId] = FfsObj
483                 if LastFfsObj != None:
484                     LastFfsObj.FreeSpace = FfsStartAddress - LastFfsObj._OFF_ - len(LastFfsObj)
485
486             FfsStartAddress += len(FfsObj)
487             #
488             # align to next 8-byte aligned address: A = (A + 8 - 1) & (~(8 - 1))
489             # The next FFS must be at the latest next 8-byte aligned address
490             #
491             FfsStartAddress = (FfsStartAddress + 7) & (~7)
492             LastFfsObj = FfsObj
493
494     def _GetAttributes(self):
495         return self.GetField(self._ATTR_, 0)[0]
496
497     def _GetSize(self):
498         return self.GetField(self._LENGTH_, 0)[0]
499
500     def _GetChecksum(self):
501         return self.GetField(self._CHECKSUM_, 0)[0]
502
503     def _GetHeaderLength(self):
504         return self.GetField(self._HLEN_, 0)[0]
505
506     def _GetFileSystemGuid(self):
507         return gGuidStringFormat % self.GetField(self._GUID_, 0)
508
509     Attributes = property(_GetAttributes)
510     Size = property(_GetSize)
511     Checksum = property(_GetChecksum)
512     HeaderSize = property(_GetHeaderLength)
513     FileSystemGuid = property(_GetFileSystemGuid)
514
515 ## CompressedImage() class
516 #
517 #  A class for Compressed Image
518 #
519 class CompressedImage(Image):
520     # UncompressedLength = 4-byte
521     # CompressionType = 1-byte
522     _HEADER_ = struct.Struct("1I 1B")
523     _HEADER_SIZE_ = _HEADER_.size
524
525     _ORIG_SIZE_     = struct.Struct("1I")
526     _CMPRS_TYPE_    = struct.Struct("4x 1B")
527
528     def __init__(m, CompressedData=None, CompressionType=None, UncompressedLength=None):
529         Image.__init__(m)
530         if UncompressedLength != None:
531             m.UncompressedLength = UncompressedLength
532         if CompressionType != None:
533             m.CompressionType = CompressionType
534         if CompressedData != None:
535             m.Data = CompressedData
536
537     def __str__(m):
538         global gIndention
539         S = "algorithm=%s uncompressed=%x" % (m.CompressionType, m.UncompressedLength)
540         for Sec in m.Sections:
541             S += '\n' + str(Sec)
542
543         return S
544
545     def _SetOriginalSize(m, Size):
546         m.SetField(m._ORIG_SIZE_, 0, Size)
547
548     def _GetOriginalSize(m):
549         return m.GetField(m._ORIG_SIZE_)[0]
550
551     def _SetCompressionType(m, Type):
552         m.SetField(m._CMPRS_TYPE_, 0, Type)
553
554     def _GetCompressionType(m):
555         return m.GetField(m._CMPRS_TYPE_)[0]
556
557     def _GetSections(m):
558         try:
559             import EfiCompressor
560             TmpData = EfiCompressor.FrameworkDecompress(
561                                         m[m._HEADER_SIZE_:],
562                                         len(m) - m._HEADER_SIZE_
563                                         )
564             DecData = array('B')
565             DecData.fromstring(TmpData)
566         except:
567             import EfiCompressor
568             TmpData = EfiCompressor.UefiDecompress(
569                                         m[m._HEADER_SIZE_:],
570                                         len(m) - m._HEADER_SIZE_
571                                         )
572             DecData = array('B')
573             DecData.fromstring(TmpData)
574
575         SectionList = []
576         Offset = 0
577         while Offset < len(DecData):
578             Sec = Section()
579             try:
580                 Sec.frombuffer(DecData, Offset)
581                 Offset += Sec.Size
582                 # the section is aligned to 4-byte boundary
583             except:
584                 break
585             SectionList.append(Sec)
586         return SectionList
587
588     UncompressedLength = property(_GetOriginalSize, _SetOriginalSize)
589     CompressionType = property(_GetCompressionType, _SetCompressionType)
590     Sections = property(_GetSections)
591
592 ## GuidDefinedImage() class
593 #
594 #  A class for GUID Defined Image
595 #
596 class GuidDefinedImage(Image):
597     _HEADER_ = struct.Struct("1I2H8B 1H 1H")
598     _HEADER_SIZE_ = _HEADER_.size
599
600     _GUID_          = struct.Struct("1I2H8B")
601     _DATA_OFFSET_   = struct.Struct("16x 1H")
602     _ATTR_          = struct.Struct("18x 1H")
603
604     CRC32_GUID          = "FC1BCDB0-7D31-49AA-936A-A4600D9DD083"
605     TIANO_COMPRESS_GUID = 'A31280AD-481E-41B6-95E8-127F4C984779'
606     LZMA_COMPRESS_GUID  = 'EE4E5898-3914-4259-9D6E-DC7BD79403CF'
607
608     def __init__(m, SectionDefinitionGuid=None, DataOffset=None, Attributes=None, Data=None):
609         Image.__init__(m)
610         if SectionDefinitionGuid != None:
611             m.SectionDefinitionGuid = SectionDefinitionGuid
612         if DataOffset != None:
613             m.DataOffset = DataOffset
614         if Attributes != None:
615             m.Attributes = Attributes
616         if Data != None:
617             m.Data = Data
618
619     def __str__(m):
620         S = "guid=%s" % (gGuidStringFormat % m.SectionDefinitionGuid)
621         for Sec in m.Sections:
622             S += "\n" + str(Sec)
623         return S
624
625     def _Unpack(m):
626         # keep header in this Image object
627         m.empty()
628         m.extend(m._BUF_[m._OFF_ : m._OFF_ + m._LEN_])
629         return len(m)
630
631     def _SetAttribute(m, Attribute):
632         m.SetField(m._ATTR_, 0, Attribute)
633
634     def _GetAttribute(m):
635         return m.GetField(m._ATTR_)[0]
636
637     def _SetGuid(m, Guid):
638         m.SetField(m._GUID_, 0, Guid)
639
640     def _GetGuid(m):
641         return m.GetField(m._GUID_)
642
643     def _SetDataOffset(m, Offset):
644         m.SetField(m._DATA_OFFSET_, 0, Offset)
645
646     def _GetDataOffset(m):
647         return m.GetField(m._DATA_OFFSET_)[0]
648
649     def _GetSections(m):
650         SectionList = []
651         Guid = gGuidStringFormat % m.SectionDefinitionGuid
652         if Guid == m.CRC32_GUID:
653             # skip the CRC32 value, we don't do CRC32 verification here
654             Offset = m.DataOffset - 4
655             while Offset < len(m):
656                 Sec = Section()
657                 try:
658                     Sec.frombuffer(m, Offset)
659                     Offset += Sec.Size
660                     # the section is aligned to 4-byte boundary
661                     Offset = (Offset + 3) & (~3)
662                 except:
663                     break
664                 SectionList.append(Sec)
665         elif Guid == m.TIANO_COMPRESS_GUID:
666             try:
667                 import EfiCompressor
668                 # skip the header
669                 Offset = m.DataOffset - 4
670                 TmpData = EfiCompressor.FrameworkDecompress(m[Offset:], len(m)-Offset)
671                 DecData = array('B')
672                 DecData.fromstring(TmpData)
673                 Offset = 0
674                 while Offset < len(DecData):
675                     Sec = Section()
676                     try:
677                         Sec.frombuffer(DecData, Offset)
678                         Offset += Sec.Size
679                         # the section is aligned to 4-byte boundary
680                         Offset = (Offset + 3) & (~3)
681                     except:
682                         break
683                     SectionList.append(Sec)
684             except:
685                 pass
686         elif Guid == m.LZMA_COMPRESS_GUID:
687             try:
688                 import LzmaCompressor
689                 # skip the header
690                 Offset = m.DataOffset - 4
691                 TmpData = LzmaCompressor.LzmaDecompress(m[Offset:], len(m)-Offset)
692                 DecData = array('B')
693                 DecData.fromstring(TmpData)
694                 Offset = 0
695                 while Offset < len(DecData):
696                     Sec = Section()
697                     try:
698                         Sec.frombuffer(DecData, Offset)
699                         Offset += Sec.Size
700                         # the section is aligned to 4-byte boundary
701                         Offset = (Offset + 3) & (~3)
702                     except:
703                         break
704                     SectionList.append(Sec)
705             except:
706                 pass
707
708         return SectionList
709
710     Attributes = property(_GetAttribute, _SetAttribute)
711     SectionDefinitionGuid = property(_GetGuid, _SetGuid)
712     DataOffset = property(_GetDataOffset, _SetDataOffset)
713     Sections = property(_GetSections)
714
715 ## Depex() class
716 #
717 #  A class for Depex
718 #
719 class Depex(Image):
720     _HEADER_ = struct.Struct("")
721     _HEADER_SIZE_ = 0
722
723     _GUID_          = struct.Struct("1I2H8B")
724     _OPCODE_        = struct.Struct("1B")
725
726     _OPCODE_STRING_ = {
727         0x00    :   "BEFORE",
728         0x01    :   "AFTER",
729         0x02    :   "PUSH",
730         0x03    :   "AND",
731         0x04    :   "OR",
732         0x05    :   "NOT",
733         0x06    :   "TRUE",
734         0x07    :   "FALSE",
735         0x08    :   "END",
736         0x09    :   "SOR"
737     }
738
739     _NEXT_ = {
740         -1      :   _OPCODE_,   # first one in depex must be an opcdoe
741         0x00    :   _GUID_,     #"BEFORE",
742         0x01    :   _GUID_,     #"AFTER",
743         0x02    :   _GUID_,     #"PUSH",
744         0x03    :   _OPCODE_,   #"AND",
745         0x04    :   _OPCODE_,   #"OR",
746         0x05    :   _OPCODE_,   #"NOT",
747         0x06    :   _OPCODE_,   #"TRUE",
748         0x07    :   _OPCODE_,   #"FALSE",
749         0x08    :   None,       #"END",
750         0x09    :   _OPCODE_,   #"SOR"
751     }
752
753     def __init__(m):
754         Image.__init__(m)
755         m._ExprList = []
756
757     def __str__(m):
758         global gIndention
759         gIndention += 4
760         Indention = ' ' * gIndention
761         S = '\n'
762         for T in m.Expression:
763             if T in m._OPCODE_STRING_:
764                 S += Indention + m._OPCODE_STRING_[T]
765                 if T not in [0x00, 0x01, 0x02]:
766                     S += '\n'
767             else:
768                 S += ' ' + gGuidStringFormat % T + '\n'
769         gIndention -= 4
770         return S
771
772     def _Unpack(m):
773         # keep header in this Image object
774         m.empty()
775         m.extend(m._BUF_[m._OFF_ : m._OFF_ + m._LEN_])
776         return len(m)
777
778     def _GetExpression(m):
779         if m._ExprList == []:
780             Offset = 0
781             CurrentData = m._OPCODE_
782             while Offset < len(m):
783                 Token = CurrentData.unpack_from(m, Offset)
784                 Offset += CurrentData.size
785                 if len(Token) == 1:
786                     Token = Token[0]
787                     if Token in m._NEXT_:
788                         CurrentData = m._NEXT_[Token]
789                     else:
790                         CurrentData = m._GUID_
791                 else:
792                     CurrentData = m._OPCODE_
793                 m._ExprList.append(Token)
794                 if CurrentData == None:
795                     break
796         return m._ExprList
797
798     Expression = property(_GetExpression)
799
800 ## Ui() class
801 #
802 #  A class for Ui
803 #
804 class Ui(Image):
805     _HEADER_ = struct.Struct("")
806     _HEADER_SIZE_ = 0
807
808     def __init__(m):
809         Image.__init__(m)
810
811     def __str__(m):
812         return m.String
813
814     def _Unpack(m):
815         # keep header in this Image object
816         m.empty()
817         m.extend(m._BUF_[m._OFF_ : m._OFF_ + m._LEN_])
818         return len(m)
819
820     def _GetUiString(m):
821         return codecs.utf_16_decode(m[0:-2].tostring())[0]
822
823     String = property(_GetUiString)
824
825 ## Section() class
826 #
827 #  A class for Section
828 #
829 class Section(Image):
830     _TypeName = {
831         0x00    :   "<unknown>",
832         0x01    :   "COMPRESSION",
833         0x02    :   "GUID_DEFINED",
834         0x10    :   "PE32",
835         0x11    :   "PIC",
836         0x12    :   "TE",
837         0x13    :   "DXE_DEPEX",
838         0x14    :   "VERSION",
839         0x15    :   "USER_INTERFACE",
840         0x16    :   "COMPATIBILITY16",
841         0x17    :   "FIRMWARE_VOLUME_IMAGE",
842         0x18    :   "FREEFORM_SUBTYPE_GUID",
843         0x19    :   "RAW",
844         0x1B    :   "PEI_DEPEX"
845     }
846
847     _SectionSubImages = {
848         0x01    :   CompressedImage,
849         0x02    :   GuidDefinedImage,
850         0x17    :   FirmwareVolume,
851         0x13    :   Depex,
852         0x1B    :   Depex,
853         0x15    :   Ui
854     }
855
856     # Size = 3-byte
857     # Type = 1-byte
858     _HEADER_ = struct.Struct("3B 1B")
859     _HEADER_SIZE_ = _HEADER_.size
860
861     # SubTypeGuid
862     # _FREE_FORM_SUBTYPE_GUID_HEADER_ = struct.Struct("1I2H8B")
863
864     _SIZE_          = struct.Struct("3B")
865     _TYPE_          = struct.Struct("3x 1B")
866
867     def __init__(m, Type=None, Size=None):
868         Image.__init__(m)
869         m._Alignment = 1
870         if Type != None:
871             m.Type = Type
872         if Size != None:
873             m.Size = Size
874
875     def __str__(m):
876         global gIndention
877         gIndention += 4
878         SectionInfo = ' ' * gIndention
879         if m.Type in m._TypeName:
880             SectionInfo += "[SECTION:%s] offset=%x size=%x" % (m._TypeName[m.Type], m._OFF_, m.Size)
881         else:
882             SectionInfo += "[SECTION:%x<unknown>] offset=%x size=%x " % (m.Type, m._OFF_, m.Size)
883         for Offset in m._SubImages:
884             SectionInfo += ", " + str(m._SubImages[Offset])
885         gIndention -= 4
886         return SectionInfo
887
888     def _Unpack(m):
889         m.empty()
890         Type, = m._TYPE_.unpack_from(m._BUF_, m._OFF_)
891         Size1, Size2, Size3 = m._SIZE_.unpack_from(m._BUF_, m._OFF_)
892         Size = Size1 + (Size2 << 8) + (Size3 << 16)
893
894         if Type not in m._SectionSubImages:
895             # no need to extract sub-image, keep all in this Image object
896             m.extend(m._BUF_[m._OFF_ : m._OFF_ + Size])
897         else:
898             # keep header in this Image object
899             m.extend(m._BUF_[m._OFF_ : m._OFF_ + m._HEADER_SIZE_])
900             #
901             # use new Image object to represent payload, which may be another kind
902             # of image such as PE32
903             #
904             PayloadOffset = m._HEADER_SIZE_
905             PayloadLen = m.Size - m._HEADER_SIZE_
906             Payload = m._SectionSubImages[m.Type]()
907             Payload.frombuffer(m._BUF_, m._OFF_ + m._HEADER_SIZE_, PayloadLen)
908             m._SubImages[PayloadOffset] = Payload
909
910         return Size
911
912     def _SetSize(m, Size):
913         Size1 = Size & 0xFF
914         Size2 = (Size & 0xFF00) >> 8
915         Size3 = (Size & 0xFF0000) >> 16
916         m.SetField(m._SIZE_, 0, Size1, Size2, Size3)
917
918     def _GetSize(m):
919         Size1, Size2, Size3 = m.GetField(m._SIZE_)
920         return Size1 + (Size2 << 8) + (Size3 << 16)
921
922     def _SetType(m, Type):
923         m.SetField(m._TYPE_, 0, Type)
924
925     def _GetType(m):
926         return m.GetField(m._TYPE_)[0]
927
928     def _GetAlignment(m):
929         return m._Alignment
930
931     def _SetAlignment(m, Alignment):
932         m._Alignment = Alignment
933         AlignmentMask = Alignment - 1
934         # section alignment is actually for payload, so we need to add header size
935         PayloadOffset = m._OFF_ + m._HEADER_SIZE_
936         if (PayloadOffset & (~AlignmentMask)) == 0:
937             return
938         NewOffset = (PayloadOffset + AlignmentMask) & (~AlignmentMask)
939         while (NewOffset - PayloadOffset) < m._HEADER_SIZE_:
940             NewOffset += m._Alignment
941
942     def tofile(m, f):
943         m.Size = len(m)
944         Image.tofile(m, f)
945         for Offset in m._SubImages:
946             m._SubImages[Offset].tofile(f)
947
948     Type = property(_GetType, _SetType)
949     Size = property(_GetSize, _SetSize)
950     Alignment = property(_GetAlignment, _SetAlignment)
951     # SubTypeGuid = property(_GetGuid, _SetGuid)
952
953 ## PadSection() class
954 #
955 #  A class for Pad Section
956 #
957 class PadSection(Section):
958     def __init__(m, Size):
959         Section.__init__(m)
960         m.Type = 0x19
961         m.Size = Size
962         m.Data = [0] * (Size - m._HEADER_SIZE_)
963
964 ## Ffs() class
965 #
966 #  A class for Ffs Section
967 #
968 class Ffs(Image):
969     _FfsFormat = "24B%(payload_size)sB"
970     # skip IntegrityCheck
971     _HEADER_ = struct.Struct("1I2H8B 2x 1B 1B 3B 1B")
972     _HEADER_SIZE_ = _HEADER_.size
973
974     _NAME_      = struct.Struct("1I2H8B")
975     _INT_CHECK_ = struct.Struct("16x 1H")
976     _TYPE_      = struct.Struct("18x 1B")
977     _ATTR_      = struct.Struct("19x 1B")
978     _SIZE_      = struct.Struct("20x 3B")
979     _STATE_     = struct.Struct("23x 1B")
980
981     VTF_GUID = "1BA0062E-C779-4582-8566-336AE8F78F09"
982
983     FFS_ATTRIB_FIXED              = 0x04
984     FFS_ATTRIB_DATA_ALIGNMENT     = 0x38
985     FFS_ATTRIB_CHECKSUM           = 0x40
986
987     _TypeName = {
988         0x00    :   "<unknown>",
989         0x01    :   "RAW",
990         0x02    :   "FREEFORM",
991         0x03    :   "SECURITY_CORE",
992         0x04    :   "PEI_CORE",
993         0x05    :   "DXE_CORE",
994         0x06    :   "PEIM",
995         0x07    :   "DRIVER",
996         0x08    :   "COMBINED_PEIM_DRIVER",
997         0x09    :   "APPLICATION",
998         0x0A    :   "SMM",
999         0x0B    :   "FIRMWARE_VOLUME_IMAGE",
1000         0x0C    :   "COMBINED_SMM_DXE",
1001         0x0D    :   "SMM_CORE",
1002         0xc0    :   "OEM_MIN",
1003         0xdf    :   "OEM_MAX",
1004         0xe0    :   "DEBUG_MIN",
1005         0xef    :   "DEBUG_MAX",
1006         0xf0    :   "FFS_MIN",
1007         0xff    :   "FFS_MAX",
1008         0xf0    :   "FFS_PAD",
1009     }
1010
1011     def __init__(self):
1012         Image.__init__(self)
1013         self.FreeSpace = 0
1014
1015         self.Sections = sdict()
1016         self.Depex = ''
1017
1018         self.__ID__ = None
1019
1020     def __str__(self):
1021         global gIndention
1022         gIndention += 4
1023         Indention = ' ' * gIndention
1024         FfsInfo = Indention
1025         FfsInfo +=  "[FFS:%s] offset=%x size=%x guid=%s free_space=%x alignment=%s\n" % \
1026                     (Ffs._TypeName[self.Type], self._OFF_, self.Size, self.Guid, self.FreeSpace, self.Alignment)
1027         SectionInfo = '\n'.join([str(self.Sections[Offset]) for Offset in self.Sections])
1028         gIndention -= 4
1029         return FfsInfo + SectionInfo + "\n"
1030
1031     def __len__(self):
1032         return self.Size
1033
1034     def __repr__(self):
1035         return self.__ID__
1036
1037     def _Unpack(self):
1038         Size1, Size2, Size3 = self._SIZE_.unpack_from(self._BUF_, self._OFF_)
1039         Size = Size1 + (Size2 << 8) + (Size3 << 16)
1040         self.empty()
1041         self.extend(self._BUF_[self._OFF_ : self._OFF_ + Size])
1042
1043         # Pad FFS may use the same GUID. We need to avoid it.
1044         if self.Type == 0xf0:
1045             self.__ID__ = str(uuid.uuid1()).upper()
1046         else:
1047             self.__ID__ = self.Guid
1048
1049         # Traverse the SECTION. RAW and PAD do not have sections
1050         if self.Type not in [0xf0, 0x01] and Size > 0 and Size < 0xFFFFFF:
1051             EndOfFfs = Size
1052             SectionStartAddress = self._HEADER_SIZE_
1053             while SectionStartAddress < EndOfFfs:
1054                 SectionObj = Section()
1055                 SectionObj.frombuffer(self, SectionStartAddress)
1056                 #f = open(repr(SectionObj), 'wb')
1057                 #SectionObj.Size = 0
1058                 #SectionObj.tofile(f)
1059                 #f.close()
1060                 self.Sections[SectionStartAddress] = SectionObj
1061                 SectionStartAddress += len(SectionObj)
1062                 SectionStartAddress = (SectionStartAddress + 3) & (~3)
1063
1064     def Pack(self):
1065         pass
1066
1067     def SetFreeSpace(self, Size):
1068         self.FreeSpace = Size
1069
1070     def _GetGuid(self):
1071         return gGuidStringFormat % self.Name
1072
1073     def _SetName(self, Value):
1074         # Guid1, Guid2, Guid3, Guid4, Guid5, Guid6, Guid7, Guid8, Guid9, Guid10, Guid11
1075         self.SetField(self._NAME_, 0, Value)
1076
1077     def _GetName(self):
1078         # Guid1, Guid2, Guid3, Guid4, Guid5, Guid6, Guid7, Guid8, Guid9, Guid10, Guid11
1079         return self.GetField(self._NAME_)
1080
1081     def _SetSize(m, Size):
1082         Size1 = Size & 0xFF
1083         Size2 = (Size & 0xFF00) >> 8
1084         Size3 = (Size & 0xFF0000) >> 16
1085         m.SetField(m._SIZE_, 0, Size1, Size2, Size3)
1086
1087     def _GetSize(m):
1088         Size1, Size2, Size3 = m.GetField(m._SIZE_)
1089         return Size1 + (Size2 << 8) + (Size3 << 16)
1090
1091     def _SetType(m, Type):
1092         m.SetField(m._TYPE_, 0, Type)
1093
1094     def _GetType(m):
1095         return m.GetField(m._TYPE_)[0]
1096
1097     def _SetAttributes(self, Value):
1098         self.SetField(m._ATTR_, 0, Value)
1099
1100     def _GetAttributes(self):
1101         return self.GetField(self._ATTR_)[0]
1102
1103     def _GetFixed(self):
1104         if (self.Attributes & self.FFS_ATTRIB_FIXED) != 0:
1105             return True
1106         return False
1107
1108     def _GetCheckSum(self):
1109         if (self.Attributes & self.FFS_ATTRIB_CHECKSUM) != 0:
1110             return True
1111         return False
1112
1113     def _GetAlignment(self):
1114         return (self.Attributes & self.FFS_ATTRIB_DATA_ALIGNMENT) >> 3
1115
1116     def _SetState(self, Value):
1117         self.SetField(m._STATE_, 0, Value)
1118
1119     def _GetState(self):
1120         return self.GetField(m._STATE_)[0]
1121
1122     Name = property(_GetName, _SetName)
1123     Guid = property(_GetGuid)
1124     Type = property(_GetType, _SetType)
1125     Size = property(_GetSize, _SetSize)
1126     Attributes = property(_GetAttributes, _SetAttributes)
1127     Fixed = property(_GetFixed)
1128     Checksum = property(_GetCheckSum)
1129     Alignment = property(_GetAlignment)
1130     State = property(_GetState, _SetState)
1131
1132 ## PeImage() class
1133 #
1134 #  A class for PE Image
1135 #
1136 class PeImage:
1137     #
1138     # just extract e_lfanew
1139     #
1140     _DosHeaderFormat = "60x 1I"
1141     #
1142     # Machine
1143     # NumberOfSections
1144     # SizeOfOptionalHeader
1145     #
1146     _FileHeaderFormat = "4x 1H 1H 4x 4x 4x 1H 2x"
1147     #
1148     # Magic
1149     # SizeOfImage
1150     # SizeOfHeaders
1151     # CheckSum
1152     # NumberOfRvaAndSizes
1153     #
1154     _OptionalHeader32Format = "1H 54x 1I 1I 1I 24x 1I"
1155     _OptionalHeader64Format = ""
1156     def __init__(self, Buf, Offset, Size):
1157         self.Offset = Offset
1158         self.Size = Size
1159         self.Machine = 0x014c # IA32
1160         self.NumberOfSections = 0
1161         self.SizeOfImage = 0
1162         self.SizeOfOptionalHeader = 0
1163         self.Checksum = 0
1164         self._PeImageBuf = Buf
1165         self._SectionList = []
1166
1167         self._DosHeader = struct.Struct(PeImage._DosHeaderFormat)
1168         self._FileHeader = struct.Struct(PeImage._FileHeaderFormat)
1169         self._OptionalHeader32 = struct.Struct(PeImage._OptionalHeader32Format)
1170
1171         self.Buffer = None
1172
1173         self._Unpack()
1174
1175     def __str__(self):
1176         pass
1177
1178     def __len__(self):
1179         return self.Size
1180
1181     def _Unpack(self):
1182         # from DOS header, get the offset of PE header
1183         FileHeaderOffset, = self._DosHeader.unpack_from(self._PeImageBuf, self.Offset)
1184         if FileHeaderOffset < struct.calcsize(self._DosHeaderFormat):
1185             EdkLogger.error("PE+", 0, "Invalid offset of IMAGE_FILE_HEADER: %s" % FileHeaderOffset)
1186
1187         # from FILE header, get the optional header size
1188         self.Machine, self.NumberOfSections, self.SizeOfOptionalHeader = \
1189             self._FileHeader.unpack_from(self._PeImageBuf, self.Offset + FileHeaderOffset)
1190
1191         print "Machine=%x NumberOfSections=%x SizeOfOptionalHeader=%x" % (self.Machine, self.NumberOfSections, self.SizeOfOptionalHeader)
1192         # optional header follows the FILE header
1193         OptionalHeaderOffset = FileHeaderOffset + struct.calcsize(self._FileHeaderFormat)
1194         Magic, self.SizeOfImage, SizeOfHeaders, self.Checksum, NumberOfRvaAndSizes = \
1195             self._OptionalHeader32.unpack_from(self._PeImageBuf, self.Offset + OptionalHeaderOffset)
1196         print "Magic=%x SizeOfImage=%x SizeOfHeaders=%x, Checksum=%x, NumberOfRvaAndSizes=%x" % (Magic, self.SizeOfImage, SizeOfHeaders, self.Checksum, NumberOfRvaAndSizes)
1197
1198         PeImageSectionTableOffset = OptionalHeaderOffset + self.SizeOfOptionalHeader
1199         PeSections = PeSectionTable(self._PeImageBuf, self.Offset + PeImageSectionTableOffset, self.NumberOfSections)
1200
1201         print "%x" % PeSections.GetFileAddress(0x3920)
1202
1203 ## PeSectionTable() class
1204 #
1205 #  A class for PE Section Table
1206 #
1207 class PeSectionTable:
1208     def __init__(self, Buf, Offset, NumberOfSections):
1209         self._SectionList = []
1210
1211         SectionHeaderOffset = Offset
1212         for TableIndex in range(0, NumberOfSections):
1213             SectionHeader = PeSectionHeader(Buf, SectionHeaderOffset)
1214             self._SectionList.append(SectionHeader)
1215             SectionHeaderOffset += len(SectionHeader)
1216             print SectionHeader
1217
1218     def GetFileAddress(self, Rva):
1219         for PeSection in self._SectionList:
1220             if Rva in PeSection:
1221                 return PeSection[Rva]
1222
1223 ## PeSectionHeader() class
1224 #
1225 #  A class for PE Section Header
1226 #
1227 class PeSectionHeader:
1228     #
1229     # VirtualAddress
1230     # SizeOfRawData
1231     # PointerToRawData
1232     #
1233     _HeaderFormat = "12x 1I 1I 1I 16x"
1234     _HeaderLength = struct.calcsize(_HeaderFormat)
1235
1236     def __init__(self, Buf, Offset):
1237         self.VirtualAddressStart, self.SizeOfRawData, self.PointerToRawData = \
1238             struct.unpack_from(self._HeaderFormat, Buf, Offset)
1239         self.VirtualAddressEnd = self.VirtualAddressStart + self.SizeOfRawData - 1
1240
1241     def __str__(self):
1242         return "VirtualAddress=%x, SizeOfRawData=%x, PointerToRawData=%x" % (self.VirtualAddressStart, self.SizeOfRawData, self.PointerToRawData)
1243
1244     def __len__(self):
1245         return self._HeaderLength
1246
1247     def __contains__(self, Rva):
1248         return Rva >= self.VirtualAddressStart and Rva <= self.VirtualAddressEnd
1249
1250     def __getitem__(self, Rva):
1251         return Rva - self.VirtualAddressStart + self.PointerToRawData
1252
1253 ## LinkMap() class
1254 #
1255 #  A class for Link Map
1256 #
1257 class LinkMap:
1258     _StartFlag = {
1259         "MSFT"  :   re.compile("Address +Publics by Value +Rva\+Base +Lib:Object"),
1260         "GCC"   :   re.compile("^\.(text|bss|data|edata)"),
1261     }
1262
1263     _MappingFormat = {
1264         "MSFT"  :   re.compile("([0-9a-f]+):([0-9a-f]+)\s+_+([0-9A-Za-z]+)\s+([0-9a-f]+)\s+"),
1265         "GCC"   :   re.compile("^(\.\w)?\s+(0x[0-9a-f]+)\s+_+([0-9A-Za-z]+)"),
1266     }
1267
1268     def __init__(self, MapFile, MapType="MSFT"):
1269         self.File = MapFile
1270         self.MapType = MapType
1271         self._Globals = {}  # global:RVA
1272
1273         self._Parse()
1274
1275     def _Parse(self):
1276         MapFile = open(self.File, 'r')
1277         MappingTitle = self._StartFlag[self.MapType]
1278         MappingFormat = self._MappingFormat[self.MapType]
1279         MappingStart = False
1280         try:
1281             for Line in MapFile:
1282                 Line = Line.strip()
1283                 if not MappingStart:
1284                     if MappingTitle.match(Line) != None:
1285                         MappingStart = True
1286                     continue
1287                 ResultList = MappingFormat.findall(Line)
1288                 if len(ResultList) == 0 or len(ResultList[0]) != 4:
1289                     continue
1290                 self._Globals[ResultList[2]] = int(ResultList[3], 16)
1291                 EdkLogger.verbose(ResultList[0])
1292         finally:
1293             MapFile.close()
1294
1295     def __contains__(self, Var):
1296         return Var in self._Globals
1297
1298     def __getitem__(self, Var):
1299         if Var not in self._Globals:
1300             return None
1301         return self._Globals[Var]
1302
1303 ## MultipleFv() class
1304 #
1305 #  A class for Multiple FV
1306 #
1307 class MultipleFv(FirmwareVolume):
1308     def __init__(self, FvList):
1309         FirmwareVolume.__init__(self)
1310         self.BasicInfo = []
1311         for FvPath in FvList:
1312             FvName = os.path.splitext(os.path.split(FvPath)[1])[0]
1313             Fd = open(FvPath, 'rb')
1314             Buf = array('B')
1315             try:
1316                 Buf.fromfile(Fd, os.path.getsize(FvPath))
1317             except EOFError:
1318                 pass
1319
1320             Fv = FirmwareVolume(FvName)
1321             Fv.frombuffer(Buf, 0, len(Buf))
1322
1323             self.BasicInfo.append([Fv.Name, Fv.FileSystemGuid, Fv.Size])
1324             self.FfsDict.append(Fv.FfsDict)
1325
1326 # Version and Copyright
1327 __version_number__ = "0.01"
1328 __version__ = "%prog Version " + __version_number__
1329 __copyright__ = "Copyright (c) 2008, Intel Corporation. All rights reserved."
1330
1331 ## Parse command line options
1332 #
1333 # Using standard Python module optparse to parse command line option of this tool.
1334 #
1335 # @retval Options   A optparse.Values object containing the parsed options
1336 # @retval InputFile Path of file to be trimmed
1337 #
1338 def GetOptions():
1339     OptionList = [
1340         make_option("-a", "--arch", dest="Arch",
1341                           help="The input file is preprocessed source code, including C or assembly code"),
1342         make_option("-p", "--platform", dest="ActivePlatform",
1343                           help="The input file is preprocessed VFR file"),
1344         make_option("-m", "--module", dest="ActiveModule",
1345                           help="Convert standard hex format (0xabcd) to MASM format (abcdh)"),
1346         make_option("-f", "--FDF-file", dest="FdfFile",
1347                           help="Convert standard hex format (0xabcd) to MASM format (abcdh)"),
1348         make_option("-o", "--output", dest="OutputDirectory",
1349                           help="File to store the trimmed content"),
1350         make_option("-t", "--toolchain-tag", dest="ToolChain",
1351                           help=""),
1352         make_option("-k", "--msft", dest="MakefileType", action="store_const", const="nmake",
1353                           help=""),
1354         make_option("-g", "--gcc", dest="MakefileType", action="store_const", const="gmake",
1355                           help=""),
1356         make_option("-v", "--verbose", dest="LogLevel", action="store_const", const=EdkLogger.VERBOSE,
1357                           help="Run verbosely"),
1358         make_option("-d", "--debug", dest="LogLevel", type="int",
1359                           help="Run with debug information"),
1360         make_option("-q", "--quiet", dest="LogLevel", action="store_const", const=EdkLogger.QUIET,
1361                           help="Run quietly"),
1362         make_option("-?", action="help", help="show this help message and exit"),
1363     ]
1364
1365     # use clearer usage to override default usage message
1366     UsageString = "%prog [-a ARCH] [-p PLATFORM] [-m MODULE] [-t TOOLCHAIN_TAG] [-k] [-g] [-v|-d <debug_level>|-q] [-o <output_directory>] [GenC|GenMake]"
1367
1368     Parser = OptionParser(description=__copyright__, version=__version__, option_list=OptionList, usage=UsageString)
1369     Parser.set_defaults(Arch=[])
1370     Parser.set_defaults(ActivePlatform=None)
1371     Parser.set_defaults(ActiveModule=None)
1372     Parser.set_defaults(OutputDirectory="build")
1373     Parser.set_defaults(FdfFile=None)
1374     Parser.set_defaults(ToolChain="MYTOOLS")
1375     if sys.platform == "win32":
1376         Parser.set_defaults(MakefileType="nmake")
1377     else:
1378         Parser.set_defaults(MakefileType="gmake")
1379     Parser.set_defaults(LogLevel=EdkLogger.INFO)
1380
1381     Options, Args = Parser.parse_args()
1382
1383     # error check
1384     if len(Args) == 0:
1385         Options.Target = "genmake"
1386         sys.argv.append("genmake")
1387     elif len(Args) == 1:
1388         Options.Target = Args[0].lower()
1389         if Options.Target not in ["genc", "genmake"]:
1390             EdkLogger.error("AutoGen", OPTION_NOT_SUPPORTED, "Not supported target",
1391                             ExtraData="%s\n\n%s" % (Options.Target, Parser.get_usage()))
1392     else:
1393         EdkLogger.error("AutoGen", OPTION_NOT_SUPPORTED, "Too many targets",
1394                         ExtraData=Parser.get_usage())
1395
1396     return Options
1397
1398 ## Entrance method
1399 #
1400 # This method mainly dispatch specific methods per the command line options.
1401 # If no error found, return zero value so the caller of this tool can know
1402 # if it's executed successfully or not.
1403 #
1404 # @retval 0     Tool was successful
1405 # @retval 1     Tool failed
1406 #
1407 def Main():
1408     from build import build
1409     try:
1410         Option = GetOptions()
1411         build.main()
1412     except Exception, e:
1413         print e
1414         return 1
1415
1416     return 0
1417
1418 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1419 if __name__ == '__main__':
1420     EdkLogger.Initialize()
1421     # sys.exit(Main())
1422
1423     if len(sys.argv) > 1:
1424         FilePath = sys.argv[1]
1425         if FilePath.lower().endswith(".fv"):
1426             fd = open(FilePath, 'rb')
1427             buf = array('B')
1428             try:
1429                 buf.fromfile(fd, os.path.getsize(FilePath))
1430             except EOFError:
1431                 pass
1432
1433             fv = FirmwareVolume("FVRECOVERY")
1434             fv.frombuffer(buf, 0, len(buf))
1435             #fv.Dispatch(None)
1436             print fv
1437         elif FilePath.endswith(".efi"):
1438             fd = open(FilePath, 'rb')
1439             buf = array('B')
1440             Size = os.path.getsize(FilePath)
1441
1442             try:
1443                 buf.fromfile(fd, Size)
1444             except EOFError:
1445                 pass
1446
1447             PeSection = Section(Type=0x10)
1448             PeSection.Data = buf
1449             sf, ext = os.path.splitext(os.path.basename(FilePath))
1450             sf += ".sec"
1451             PeSection.tofile(open(sf, 'wb'))
1452         elif FilePath.endswith(".map"):
1453             mf = LinkMap(FilePath)