From 8d9b898cb56718e719414e15881d315954d6130a Mon Sep 17 00:00:00 2001 From: YuweiChen1110 Date: Mon, 5 Jun 2023 11:47:25 +0800 Subject: [PATCH] Fmmt enhancement (#95) * BaseTools: fixing FMMT ShrinkFv issue 1. FvLength not change issue; 2. FileSystemGuid align with File Size; Cc: Rebecca Cran Cc: Liming Gao Cc: Bob Feng Signed-off-by: Yuwei Chen * BaseTools: FMMT replace output file is not generated successfully For replace function, when target Ffs and new ffs are with same size, the output file can not be generated successfully. This patch fixes this issue. Cc: Rebecca Cran Cc: Bob Feng Cc: Liming Gao Signed-off-by: Yuwei Chen * BaseTools: FMMT support ELF UPLD parser FMMT add new function to support the .elf file parsing. Using '-v' option, the UPLD info will be printed out. ''' - UNIVERSAL_PAYLOAD_INFO - 4 bytes align (BOOLEAN) - Identifier - SpecRevision - Attribute - Revision - Capability - ProducerId - ImageId UPLD Buffer ''' Cc: Rebecca Cran Cc: Bob Feng Cc: Liming Gao Signed-off-by: Yuwei Chen --------- Signed-off-by: Yuwei Chen --- edk2basetools/FMMT/FMMT.py | 2 + .../FMMT/core/BinaryFactoryProduct.py | 36 ++- edk2basetools/FMMT/core/BiosTree.py | 52 +++- edk2basetools/FMMT/core/BiosTreeNode.py | 56 +++- edk2basetools/FMMT/core/FMMTOperation.py | 2 +- edk2basetools/FMMT/core/FMMTParser.py | 2 +- edk2basetools/FMMT/core/FvHandler.py | 28 +- .../FirmwareStorageFormat/UPLHeader.py | 244 ++++++++++++++++++ 8 files changed, 408 insertions(+), 14 deletions(-) create mode 100644 edk2basetools/FirmwareStorageFormat/UPLHeader.py diff --git a/edk2basetools/FMMT/FMMT.py b/edk2basetools/FMMT/FMMT.py index 5f2c8eb9..29aec65f 100644 --- a/edk2basetools/FMMT/FMMT.py +++ b/edk2basetools/FMMT/FMMT.py @@ -84,6 +84,8 @@ def View(self, inputfile: str, layoutfilename: str=None, outputfile: str=None) - ROOT_TYPE = ROOT_FFS_TREE elif filetype == '.sec': ROOT_TYPE = ROOT_SECTION_TREE + elif filetype == '.elf': + ROOT_TYPE = ROOT_ELF_TREE else: ROOT_TYPE = ROOT_TREE ViewFile(inputfile, ROOT_TYPE, layoutfilename, outputfile) diff --git a/edk2basetools/FMMT/core/BinaryFactoryProduct.py b/edk2basetools/FMMT/core/BinaryFactoryProduct.py index ecae1ca9..9eca6c19 100644 --- a/edk2basetools/FMMT/core/BinaryFactoryProduct.py +++ b/edk2basetools/FMMT/core/BinaryFactoryProduct.py @@ -15,10 +15,13 @@ from utils.FmmtLogger import FmmtLogger as logger ROOT_TREE = 'ROOT' +ROOT_ELF_TREE = 'ROOT_ELF_TREE' ROOT_FV_TREE = 'ROOT_FV_TREE' ROOT_FFS_TREE = 'ROOT_FFS_TREE' ROOT_SECTION_TREE = 'ROOT_SECTION_TREE' +ELF_TREE = 'ELF' +ELF_SECTION_TREE = 'ELF_SECTION_TREE' FV_TREE = 'FV' DATA_FV_TREE = 'DATA_FV' FFS_TREE = 'FFS' @@ -49,6 +52,12 @@ def DeCompressData(self, GuidTool, Section_Data: bytes, FileName) -> bytes: def ParserData(): pass +class ElfFactory(BinaryFactory): + type = [ROOT_ELF_TREE, ELF_TREE] + + def Create_Product(): + return ElfProduct() + class SectionFactory(BinaryFactory): type = [SECTION_TREE] @@ -354,6 +363,30 @@ def GetFvFromFd(self, whole_data: bytes=b'') -> list: tmp_index += 1 return Fd_Struct +class ElfSectionProduct(BinaryProduct): + ## Decompress the compressed section. + def ParserData(self, Section_Tree, whole_Data: bytes, Rel_Whole_Offset: int=0) -> None: + pass + def ParserSectionData(self, Section_Tree, whole_Data: bytes, Rel_Whole_Offset: int=0) -> None: + pass + def ParserProgramData(self, Section_Tree, whole_Data: bytes, Rel_Whole_Offset: int=0) -> None: + pass + +class ElfProduct(BinaryProduct): + + def ParserData(self, ParTree, Whole_Data: bytes, Rel_Whole_Offset: int=0) -> None: + Elf_Info = ElfNode(Whole_Data) + if Elf_Info.Header.ELF_PHOff != 0: + Elf_Info.GetProgramList(Whole_Data[Elf_Info.Header.ELF_PHOff:]) + if Elf_Info.Header.ELF_SHOff != 0: + Elf_Info.GetSectionList(Whole_Data[Elf_Info.Header.ELF_SHOff:]) + Elf_Info.FindUPLDSection(Whole_Data) + Elf_Tree = BIOSTREE(Elf_Info.Name) + Elf_Tree.type = ELF_TREE + Elf_Info.Data = Whole_Data[Elf_Info.HeaderLength:] + Elf_Tree.Data = Elf_Info + ParTree.insertChild(Elf_Tree) + class ParserEntry(): FactoryTable:dict = { SECTION_TREE: SectionFactory, @@ -364,6 +397,7 @@ class ParserEntry(): SEC_FV_TREE: FvFactory, ROOT_FV_TREE: FdFactory, ROOT_TREE: FdFactory, + ROOT_ELF_TREE: ElfFactory, } def GetTargetFactory(self, Tree_type: str) -> BinaryFactory: @@ -377,4 +411,4 @@ def Generate_Product(self, TargetFactory: BinaryFactory, Tree, Data: bytes, Offs def DataParser(self, Tree, Data: bytes, Offset: int) -> None: TargetFactory = self.GetTargetFactory(Tree.type) if TargetFactory: - self.Generate_Product(TargetFactory, Tree, Data, Offset) \ No newline at end of file + self.Generate_Product(TargetFactory, Tree, Data, Offset) diff --git a/edk2basetools/FMMT/core/BiosTree.py b/edk2basetools/FMMT/core/BiosTree.py index ae889f68..f776519b 100644 --- a/edk2basetools/FMMT/core/BiosTree.py +++ b/edk2basetools/FMMT/core/BiosTree.py @@ -12,6 +12,7 @@ ROOT_FV_TREE = 'ROOT_FV_TREE' ROOT_FFS_TREE = 'ROOT_FFS_TREE' ROOT_SECTION_TREE = 'ROOT_SECTION_TREE' +ROOT_ELF_TREE = 'ROOT_ELF_TREE' FV_TREE = 'FV' DATA_FV_TREE = 'DATA_FV' @@ -21,11 +22,13 @@ SECTION_TREE = 'SECTION' SEC_FV_TREE = 'SEC_FV_IMAGE' BINARY_DATA = 'BINARY' +ELF_TREE = 'ELF' RootType = [ROOT_TREE, ROOT_FV_TREE, ROOT_FFS_TREE, ROOT_SECTION_TREE] FvType = [FV_TREE, SEC_FV_TREE] FfsType = FFS_TREE SecType = SECTION_TREE +ElfType = [ROOT_ELF_TREE, ELF_TREE] class BIOSTREE: def __init__(self, NodeName: str) -> None: @@ -56,7 +59,7 @@ def insertChild(self, newNode, pos: int=None) -> None: if len(self.Child) == 0: self.Child.append(newNode) else: - if not pos: + if not pos or pos == len(self.Child): LastTree = self.Child[-1] self.Child.append(newNode) LastTree.NextRel = newNode @@ -118,6 +121,31 @@ def parserTree(self, TargetDict: dict=None, Info: list=None, space: int=0, ParFv Info.append("Image File: {}".format(Key)) Info.append("FilesNum: {}".format(TargetDict.get(Key).get('FilesNum'))) Info.append("\n") + elif TargetDict[Key]["Type"] == ROOT_ELF_TREE: + Info.append("ELF File: {}\n".format(Key)) + elif TargetDict[Key]["Type"] == ELF_TREE: + ProducerId = "" + ImageId = "" + if TargetDict.get(Key).get('IfExist'): + Identifier = TargetDict.get(Key).get('Identifier') + for item in TargetDict.get(Key).get('ProducerId'): + ProducerId += chr(item) + for item in TargetDict.get(Key).get('ImageId'): + ImageId += chr(item) + Info.append("- UNIVERSAL_PAYLOAD_INFO") + Info.append(" - 4 bytes align: {}".format(TargetDict.get(Key).get('Upld_Info_Align'))) + Info.append(" - Identifier: {} # 0x48444c50--PLDH / 0x444c5055--UPLD".format(hex(Identifier))) + Info.append(" - SpecRevision: {}".format(hex(TargetDict.get(Key).get('SpecRevision')))) + Info.append(" - Attribute: {}".format(hex(TargetDict.get(Key).get('Attribute')))) + Info.append(" - Revision: {}".format(hex(TargetDict.get(Key).get('Revision')))) + Info.append(" - Capability: {}".format(hex(TargetDict.get(Key).get('Capability')))) + Info.append(" - ProducerId: {}".format(ProducerId)) + Info.append(" - ImageId: {}".format(ImageId)) + Info.append("\n") + Info.append("- UPLD buffer") + Info.append(" Buffer: {}".format(TargetDict.get(Key).get('Upld_Buffer'))) + else: + print("Do not find the Upld Info section!!!\n") elif TargetDict[Key]["Type"] in FvType: space += 2 if TargetDict[Key]["Type"] == SEC_FV_TREE: @@ -146,13 +174,29 @@ def ExportTree(self,TreeInfo: dict=None) -> dict: if TreeInfo is None: TreeInfo =collections.OrderedDict() - if self.type == ROOT_TREE or self.type == ROOT_FV_TREE or self.type == ROOT_FFS_TREE or self.type == ROOT_SECTION_TREE: + if self.type == ROOT_TREE or self.type == ROOT_FV_TREE or self.type == ROOT_FFS_TREE or self.type == ROOT_SECTION_TREE or self.type == ROOT_ELF_TREE: key = str(self.key) TreeInfo[self.key] = collections.OrderedDict() TreeInfo[self.key]["Name"] = key TreeInfo[self.key]["Type"] = self.type TreeInfo[self.key]["FilesNum"] = len(self.Child) - elif self.type == FV_TREE or self.type == SEC_FV_TREE: + elif self.type == ELF_TREE: + key = str(self.Data.Name) + TreeInfo[key] = collections.OrderedDict() + TreeInfo[key]["Name"] = key + TreeInfo[key]["Type"] = self.type + TreeInfo[key]["IfExist"] = self.Data.UpldInfo + if self.Data.UpldInfo: + TreeInfo[key]["Identifier"] = self.Data.UpldInfo.Identifier + TreeInfo[key]["SpecRevision"] = self.Data.UpldInfo.SpecRevision + TreeInfo[key]["Attribute"] = self.Data.UpldInfo.Attribute + TreeInfo[key]["Revision"] = self.Data.UpldInfo.Revision + TreeInfo[key]["Capability"] = self.Data.UpldInfo.Capability + TreeInfo[key]["ProducerId"] = self.Data.UpldInfo.ProducerId + TreeInfo[key]["ImageId"] = self.Data.UpldInfo.ImageId + TreeInfo[key]["Upld_Info_Align"] = self.Data.Upld_Info_Align + TreeInfo[key]["Upld_Buffer"] = self.Data.UpldBuffer + elif self.type == FV_TREE or self.type == SEC_FV_TREE: key = str(self.Data.FvId) TreeInfo[key] = collections.OrderedDict() TreeInfo[key]["Name"] = key @@ -195,4 +239,4 @@ def ExportTree(self,TreeInfo: dict=None) -> dict: for item in self.Child: TreeInfo[key].setdefault('Files',[]).append( item.ExportTree()) - return TreeInfo \ No newline at end of file + return TreeInfo diff --git a/edk2basetools/FMMT/core/BiosTreeNode.py b/edk2basetools/FMMT/core/BiosTreeNode.py index 670c7d79..ba6a027c 100644 --- a/edk2basetools/FMMT/core/BiosTreeNode.py +++ b/edk2basetools/FMMT/core/BiosTreeNode.py @@ -4,6 +4,7 @@ # Copyright (c) 2021-, Intel Corporation. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent ## +from FirmwareStorageFormat.UPLHeader import * from FirmwareStorageFormat.FvHeader import * from FirmwareStorageFormat.FfsFileHeader import * from FirmwareStorageFormat.SectionHeader import * @@ -37,6 +38,59 @@ def __init__(self, name: str) -> None: self.HOffset = 0 self.Data = b'' +class ElfNode: + def __init__(self, buffer: bytes) -> None: + self.Header = ELF_HEADER32.from_buffer_copy(buffer) + if self.Header.ELF_Identification[0:4] != b'\x7fELF': + logger.error('Invalid Elf Header! Elf Identification {} is not ".ELF".'.format(self.Header.ELF_Identification)) + raise Exception("Process Failed: Invalid ELF Header Identification!") + self.Class = self.Header.ELF_Identification[4] + if self.Class == 0x02: + self.Header = ELF_HEADER64.from_buffer_copy(buffer) + elif self.Class != 0x01: + logger.error('Invalid Elf Class! Elf Class {} is not 0x01 or 0x02.'.format(self.Class)) + raise Exception("Process Failed: Invalid ELF Class!") + + self.ProList = [] + self.SecList = [] + self.UpldInfoSection = None + self.UpldInfo = None + self.UpldBuffer = b'' + self.Name = "ELF" + self.HeaderLength = len(struct2stream(self.Header)) + self.HOffset = 0 + self.DOffset = 0 + self.ROffset = 0 + self.Data = b'' + self.PadData = b'' + self.Upld_Info_Align = False + + def GetProgramList(self, buffer: bytes) -> None: + for i in range(self.Header.ELF_PHNum): + if self.Class == 0x01: + ElfProgramHeader = ELF_PROGRAM_HEADER32.from_buffer_copy(buffer[i*self.Header.ELF_PHEntSize:]) + elif self.Class == 0x02: + ElfProgramHeader = ELF_PROGRAM_HEADER64.from_buffer_copy(buffer[i*self.Header.ELF_PHEntSize:]) + self.ProList.append(ElfProgramHeader) + + def GetSectionList(self, buffer: bytes) -> None: + for i in range(self.Header.ELF_SHNum): + if self.Class == 0x01: + ElfSectionHeader = ELF_SECTION_HEADER32.from_buffer_copy(buffer[i*self.Header.ELF_SHEntSize:]) + elif self.Class == 0x02: + ElfSectionHeader = ELF_SECTION_HEADER64.from_buffer_copy(buffer[i*self.Header.ELF_SHEntSize:]) + self.SecList.append(ElfSectionHeader) + + def FindUPLDSection(self, buffer: bytes) -> None: + for item in self.SecList: + if buffer[item.SH_Offset:item.SH_Offset+4] == b'PLDH' or buffer[item.SH_Offset:item.SH_Offset+4] == b'UPLD': + self.UpldInfoSection = item + self.UpldInfo = UNIVERSAL_PAYLOAD_INFO.from_buffer_copy(buffer[item.SH_Offset:item.SH_Offset+item.SH_Size]) + self.UpldBuffer = struct2stream(self.UpldInfo) + if (self.UpldInfoSection.SH_Offset) % 4 == 0: + # if (self.UpldInfoSection.SH_Offset - self.Header.ELF_Entry) % 4 == 0: + self.Upld_Info_Align = True + class FvNode: def __init__(self, name, buffer: bytes) -> None: self.Header = EFI_FIRMWARE_VOLUME_HEADER.from_buffer_copy(buffer) @@ -191,4 +245,4 @@ def __init__(self, buffer: bytes) -> None: self.HOffset = 0 self.DOffset = 0 self.ROffset = 0 - self.PadData = b'' \ No newline at end of file + self.PadData = b'' diff --git a/edk2basetools/FMMT/core/FMMTOperation.py b/edk2basetools/FMMT/core/FMMTOperation.py index 4a12d491..d9ab6f69 100644 --- a/edk2basetools/FMMT/core/FMMTOperation.py +++ b/edk2basetools/FMMT/core/FMMTOperation.py @@ -188,7 +188,7 @@ def ExtractFfs(inputfile: str, Ffs_name: str, outputfile: str, Fv_name: str=None FmmtParser.WholeFvTree.Findlist.remove(FmmtParser.WholeFvTree.Findlist[index]) if FmmtParser.WholeFvTree.Findlist != []: TargetNode = FmmtParser.WholeFvTree.Findlist[0] - if TargetNode.type == FV_TREE or SEC_FV_TREE or DATA_FV_TREE: + if TargetNode.type == FV_TREE or TargetNode.type == SEC_FV_TREE or TargetNode.type == DATA_FV_TREE: FinalData = struct2stream(TargetNode.Data.Header) + TargetNode.Data.Data with open(outputfile, "wb") as f: f.write(FinalData) diff --git a/edk2basetools/FMMT/core/FMMTParser.py b/edk2basetools/FMMT/core/FMMTParser.py index dd71cf3f..18de96c0 100644 --- a/edk2basetools/FMMT/core/FMMTParser.py +++ b/edk2basetools/FMMT/core/FMMTParser.py @@ -20,7 +20,7 @@ def __init__(self, name: str, TYPE: str) -> None: ## Parser the nodes in WholeTree. def ParserFromRoot(self, WholeFvTree=None, whole_data: bytes=b'', Reloffset: int=0) -> None: - if WholeFvTree.type == ROOT_TREE or WholeFvTree.type == ROOT_FV_TREE: + if WholeFvTree.type == ROOT_TREE or WholeFvTree.type == ROOT_FV_TREE or WholeFvTree.type == ROOT_ELF_TREE: ParserEntry().DataParser(self.WholeFvTree, whole_data, Reloffset) else: ParserEntry().DataParser(WholeFvTree, whole_data, Reloffset) diff --git a/edk2basetools/FMMT/core/FvHandler.py b/edk2basetools/FMMT/core/FvHandler.py index dc303c2c..207b7c97 100644 --- a/edk2basetools/FMMT/core/FvHandler.py +++ b/edk2basetools/FMMT/core/FvHandler.py @@ -279,7 +279,7 @@ def ModifyTest(self, ParTree, Needed_Space: int) -> None: ParTree.Child.remove(ParTree.Child[-1]) ParTree.Data.Free_Space = 0 ParTree.Data.Size += Needed_Space - ParTree.Data.Header.Fvlength = ParTree.Data.Size + ParTree.Data.Header.FvLength = ParTree.Data.Size ModifyFvSystemGuid(ParTree) for item in ParTree.Child: if item.type == FFS_FREE_SPACE: @@ -387,7 +387,21 @@ def ReplaceFfs(self) -> bool: if self.NewFfs.Data.Size >= self.TargetFfs.Data.Size: Needed_Space = self.NewFfs.Data.Size + len(self.NewFfs.Data.PadData) - self.TargetFfs.Data.Size - len(self.TargetFfs.Data.PadData) # If TargetFv have enough free space, just move part of the free space to NewFfs. - if TargetFv.Data.Free_Space >= Needed_Space: + if Needed_Space == 0: + Target_index = TargetFv.Child.index(self.TargetFfs) + TargetFv.Child.remove(self.TargetFfs) + TargetFv.insertChild(self.NewFfs, Target_index) + # Modify TargetFv Header and ExtHeader info. + TargetFv.Data.ModFvExt() + TargetFv.Data.ModFvSize() + TargetFv.Data.ModExtHeaderData() + ModifyFvExtData(TargetFv) + TargetFv.Data.ModCheckSum() + # Recompress from the Fv node to update all the related node data. + self.CompressData(TargetFv) + # return the Status + self.Status = True + elif TargetFv.Data.Free_Space >= Needed_Space: # Modify TargetFv Child info and BiosTree. TargetFv.Child[-1].Data.Data = b'\xff' * (TargetFv.Data.Free_Space - Needed_Space) TargetFv.Data.Free_Space -= Needed_Space @@ -450,7 +464,6 @@ def ReplaceFfs(self) -> bool: Target_index = TargetFv.Child.index(self.TargetFfs) TargetFv.Child.remove(self.TargetFfs) TargetFv.insertChild(self.NewFfs, Target_index) - self.Status = True # If TargetFv do not have free space, create free space for Fv. else: New_Free_Space_Tree = BIOSTREE('FREE_SPACE') @@ -461,7 +474,6 @@ def ReplaceFfs(self) -> bool: Target_index = TargetFv.Child.index(self.TargetFfs) TargetFv.Child.remove(self.TargetFfs) TargetFv.insertChild(self.NewFfs, Target_index) - self.Status = True # Modify TargetFv Header and ExtHeader info. TargetFv.Data.ModFvExt() TargetFv.Data.ModFvSize() @@ -470,6 +482,7 @@ def ReplaceFfs(self) -> bool: TargetFv.Data.ModCheckSum() # Recompress from the Fv node to update all the related node data. self.CompressData(TargetFv) + self.Status = True logger.debug('Done!') return self.Status @@ -650,8 +663,11 @@ def ShrinkFv(self) -> bool: Removed_Space = TargetFv.Data.Free_Space - New_Free_Space TargetFv.Child[-1].Data.Data = b'\xff' * New_Free_Space TargetFv.Data.Size -= Removed_Space - TargetFv.Data.Header.Fvlength = TargetFv.Data.Size - ModifyFvSystemGuid(TargetFv) + TargetFv.Data.Header.FvLength = TargetFv.Data.Size + if struct2stream(TargetFv.Data.Header.FileSystemGuid) == EFI_FIRMWARE_FILE_SYSTEM3_GUID_BYTE: + if TargetFv.Data.Size <= 0xFFFFFF: + TargetFv.Data.Header.FileSystemGuid = ModifyGuidFormat( + "8c8ce578-8a3d-4f1c-9935-896185c32dd3") for item in TargetFv.Child: if item.type == FFS_FREE_SPACE: TargetFv.Data.Data += item.Data.Data + item.Data.PadData diff --git a/edk2basetools/FirmwareStorageFormat/UPLHeader.py b/edk2basetools/FirmwareStorageFormat/UPLHeader.py new file mode 100644 index 00000000..06e73a11 --- /dev/null +++ b/edk2basetools/FirmwareStorageFormat/UPLHeader.py @@ -0,0 +1,244 @@ +## @file +# This file is used to define the UPL Header C Struct. +# +# Copyright (c) 2023-, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## +from struct import * +from ctypes import * +from FirmwareStorageFormat.Common import * + +EFI_COMMON_SECTION_HEADER_LEN = 4 +EFI_COMMON_SECTION_HEADER2_LEN = 8 + +# ELF header. +class ELF_HEADER32(Structure): + _pack_ = 1 + _fields_ = [ + ('ELF_Identification', ARRAY(c_char, 16)), # /* File identification. */ + ('ELF_Type', c_uint16), # Elf32_Half /* File type. */ + ('ELF_Machine', c_uint16), # Elf32_Half /* Machine architecture. */ + ('ELF_Version', c_uint32), # Elf32_Word /* ELF format version. */ + ('ELF_Entry', c_uint32), # Elf32_Addr /* Entry point. */ + ('ELF_PHOff', c_uint32), # Elf32_Off /* Program header file offset. */ + ('ELF_SHOff', c_uint32), # Elf32_Off /* Section header file offset. */ + ('ELF_Flags', c_uint32), # Elf32_Word /* Architecture-specific flags. */ + ('ELF_EFSize', c_uint16), # Elf32_Half /* Size of ELF header in bytes. */ + ('ELF_PHEntSize', c_uint16), # Elf32_Half /* Size of program header entry. */ + ('ELF_PHNum', c_uint16), # Elf32_Half /* Number of program header entries. */ + ('ELF_SHEntSize', c_uint16), # Elf32_Half /* Size of section header entry. */ + ('ELF_SHNum', c_uint16), # Elf32_Half /* Number of section header entries. */ + ('ELF_SNStr', c_uint16), # Elf32_Half /* Section name strings section. */ + ] + +class ELF_HEADER64(Structure): + _pack_ = 1 + _fields_ = [ + ('ELF_Identification', ARRAY(c_char, 16)), # /* File identification. */ + ('ELF_Type', c_uint16), # Elf64_Half /* File type. */ + ('ELF_Machine', c_uint16), # Elf64_Half /* Machine architecture. */ + ('ELF_Version', c_uint32), # Elf64_Word /* ELF format version. */ + ('ELF_Entry', c_uint64), # Elf64_Addr /* Entry point. */ + ('ELF_PHOff', c_uint64), # Elf64_Off /* Program header file offset. */ + ('ELF_SHOff', c_uint64), # Elf64_Off /* Section header file offset. */ + ('ELF_Flags', c_uint32), # Elf64_Word /* Architecture-specific flags. */ + ('ELF_EFSize', c_uint16), # Elf64_Half /* Size of ELF header in bytes. */ + ('ELF_PHEntSize', c_uint16), # Elf64_Half /* Size of program header entry. */ + ('ELF_PHNum', c_uint16), # Elf64_Half /* Number of program header entries. */ + ('ELF_SHEntSize', c_uint16), # Elf64_Half /* Size of section header entry. */ + ('ELF_SHNum', c_uint16), # Elf64_Half /* Number of section header entries. */ + ('ELF_SNStr', c_uint16), # Elf64_Half /* Section name strings section. */ + ] + +# Section header. +class ELF_SECTION_HEADER32(Structure): + _pack_ = 1 + _fields_ = [ + ('SH_Name', c_uint32), # Elf32_Word /* Section name (index into the section header string table). */ + ('SH_Type', c_uint32), # Elf32_Word /* Section type. */ + ('SH_Flags', c_uint32), # Elf32_Word /* Section flags. */ + ('SH_ADDR', c_uint32), # Elf32_Addr /* Address in memory image. */ + ('SH_Offset', c_uint32), # Elf32_Off /* Offset in file. */ + ('SH_Size', c_uint32), # Elf32_Word /* Size in bytes. */ + ('SH_Link', c_uint32), # Elf32_Word /* Index of a related section. */ + ('SH_Info', c_uint32), # Elf32_Word /* Depends on section type. */ + ('SH_AddrAlign', c_uint32), # Elf32_Word /* Alignment in bytes. */ + ('SH_EntSize', c_uint32), # Elf32_Word /* Size of each entry in section. */ + ] + +class ELF_SECTION_HEADER64(Structure): + _pack_ = 1 + _fields_ = [ + ('SH_Name', c_uint32), # Elf32_Word /* Section name (index into the section header string table). */ + ('SH_Type', c_uint32), # Elf32_Word /* Section type. */ + ('SH_Flags', c_uint64), # Elf32_XWord /* Section flags. */ + ('SH_ADDR', c_uint64), # Elf32_Addr /* Address in memory image. */ + ('SH_Offset', c_uint64), # Elf32_Off /* Offset in file. */ + ('SH_Size', c_uint64), # Elf32_XWord /* Size in bytes. */ + ('SH_Link', c_uint32), # Elf32_Word /* Index of a related section. */ + ('SH_Info', c_uint32), # Elf32_Word /* Depends on section type. */ + ('SH_AddrAlign', c_uint64), # Elf32_XWord /* Alignment in bytes. */ + ('SH_EntSize', c_uint64), # Elf32_XWord /* Size of each entry in section. */ + ] + +# Program header. +class ELF_PROGRAM_HEADER32(Structure): + _pack_ = 1 + _fields_ = [ + ('PH_Type', c_uint32), # Elf32_Word /* Entry type. */ + ('PH_Offset', c_uint32), # Elf32_Off /* File offset of contents. */ + ('PH_VirAddr', c_uint32), # Elf32_Addr /* Virtual address in memory image. */ + ('PH_PhyAddr', c_uint32), # Elf32_Addr /* Physical address (not used). */ + ('PH_FileSize', c_uint32), # Elf32_Word /* Size of contents in file. */ + ('PH_MemorySize', c_uint32), # Elf32_Word /* Size of contents in memory. */ + ('PH_Flags', c_uint32), # Elf32_Word /* Access permission flags. */ + ('PH_Align', c_uint32), # Elf32_Word /* Alignment in memory and file. */ + ] + +class ELF_PROGRAM_HEADER64(Structure): + _pack_ = 1 + _fields_ = [ + ('PH_Type', c_uint32), # Elf32_Word /* Entry type. */ + ('PH_Flags', c_uint32), # Elf32_Word /* Access permission flags. */ + ('PH_Offset', c_uint64), # Elf32_Off /* File offset of contents. */ + ('PH_VirAddr', c_uint64), # Elf32_Addr /* Virtual address in memory image. */ + ('PH_PhyAddr', c_uint64), # Elf32_Addr /* Physical address (not used). */ + ('PH_FileSize', c_uint64), # Elf32_XWord /* Size of contents in file. */ + ('PH_MemorySize', c_uint64), # Elf32_XWord /* Size of contents in memory. */ + ('PH_Align', c_uint64), # Elf32_XWord /* Alignment in memory and file. */ + ] + +# Dynamic union. +class ELF_DYNAMIC_UNION(Structure): + _pack_ = 1 + _fields_ = [ + ('ELF_Dynamic_Val', c_uint32), # Elf32_Word /* Integer value. */ + ('ELF_Dynamic_Ptr', c_uint32), # Elf32_Addr /* Address value. */ + ] + + +# Dynamic structure. The ".dynamic" section contains an array of them. +class ELF_DYNAMIC_STRUCTURE(Structure): + _pack_ = 1 + _fields_ = [ + ('ELF_Dynamic_Tag', c_int32), # Elf32_Sword /* Entry type. */ + ('ELF_Dynamic_Union', ELF_DYNAMIC_UNION), # Elf32_Off /* Section type. */ + ] + +## Relocation entries. + +# /* Relocations that don't need an addend field. */ +class ELF_RELOCATION(Structure): + _pack_ = 1 + _fields_ = [ + ('ELF_ReOffset', c_uint32), # Elf32_Addr /* Location to be relocated. */ + ('ELF_ReInfo', c_uint32), # Elf32_Word /* Relocation type and symbol index. */ + ] + +# /* Relocations that need an addend field. */ +class ELF_RELOCATION(Structure): + _pack_ = 1 + _fields_ = [ + ('ELF_ReOffset', c_uint32), # Elf32_Addr /* Location to be relocated. */ + ('ELF_ReInfo', c_uint32), # Elf32_Word /* Relocation type and symbol index. */ + ('ELF_ReAddend', c_int32), # Elf32_SWord /* Addend. */ + ] + +# Move Entry +class ELF_MOVE(Structure): + _pack_ = 1 + _fields_ = [ + ('ELF_MValue', c_uint64), # Elf32_Lword /* symbol value */ + ('ELF_MInfo', c_uint32), # Elf32_Word /* size + index */ + ('ELF_MPOffset', c_int32), # Elf32_Word /* symbol offset */ + ('ELF_MRepeat', c_uint16), # Elf32_Half /* repeat count */ + ('ELF_MStride', c_uint16), # Elf32_Half /* stride info */ + ] + +## Hardware/Software capabilities entry +class ELF_CAPA_UNION(Structure): + _pack_ = 1 + _fields_ = [ + ('ELF_Capa_Val', c_uint32), # Elf32_Word /* Integer value. */ + ('ELF_Capa_Ptr', c_uint32), # Elf32_Addr /* Address value. */ + ] + +class ELF_CAPABILITY(Structure): + _pack_ = 1 + _fields_ = [ + ('ELF_Capa_Tag', c_uint32), # Elf32_Word /* how to interpret value */ + ('ELF_Capa_Union', ELF_CAPA_UNION), # ELF_CAPA_UNION + ] + +# Symbol table entries. +class ELF_SYMBOL(Structure): + _pack_ = 1 + _fields_ = [ + ('ELF_ST_Name', c_uint32), # Elf32_Word /* String table index of name. */ + ('ELF_ST_Value', c_uint32), # Elf32_Addr /* Symbol value. */ + ('ELF_ST_Size', c_uint32), # Elf32_Word /* Size of associated object. */ + ('ELF_ST_Info', c_char), # /* Type and binding information. */ + ('ELF_ST_Other', c_char), # /* Reserved (not used). */ + ('ELF_ST_Shndx', c_uint16), # Elf32_Half /* Section index of symbol. */ + ] + +# Structures used by Sun & GNU symbol versioning. +class ELF_VERDEF(Structure): + _pack_ = 1 + _fields_ = [ + ('ELF_VD_Version', c_uint16), # Elf32_Half + ('ELF_VD_Flags', c_uint16), # Elf32_Half + ('ELF_VD_Ndx', c_uint16), # Elf32_Half + ('ELF_VD_Cnt', c_uint16), # Elf32_Half + ('ELF_VD_Hash', c_uint32), # Elf32_Word + ('ELF_VD_Aux', c_uint32), # Elf32_Word + ('ELF_VD_Next', c_uint32), # Elf32_Word + ] + +class ELF_VERDAUX(Structure): + _pack_ = 1 + _fields_ = [ + ('ELF_VDA_Name', c_uint32), # Elf32_Word + ('ELF_VDA_Next', c_uint32), # Elf32_Word + ] + +class ELF_VERNEED(Structure): + _pack_ = 1 + _fields_ = [ + ('ELF_VN_Version', c_uint16), # Elf32_Half + ('ELF_VN_Cnt', c_uint16), # Elf32_Half + ('ELF_VN_File', c_uint32), # Elf32_Word + ('ELF_VN_Aux', c_uint32), # Elf32_Word + ('ELF_VN_Next', c_uint32), # Elf32_Word + ] + +class ELF_VERNAUX(Structure): + _pack_ = 1 + _fields_ = [ + ('ELF_VNA_Hash', c_uint32), # Elf32_Word + ('ELF_VNA_Flags', c_uint16), # Elf32_Half + ('ELF_VNA_Other', c_uint16), # Elf32_Half + ('ELF_VNA_Name', c_uint32), # Elf32_Word + ('ELF_VNA_Next', c_uint32), # Elf32_Word + ] + +class ELF_SYMINFO(Structure): + _pack_ = 1 + _fields_ = [ + ('ELF_SI_BoundTo', c_uint16), # Elf32_Half /* direct bindings - symbol bound to */ + ('ELF_SI_Flags', c_uint16), # Elf32_Half /* per symbol flags */ + ] + +class UNIVERSAL_PAYLOAD_INFO(Structure): + _pack_ = 1 + _fields_ = [ + ('Identifier', c_uint32), # ‘PLDH’ Identifier for the unverial payload info. 0x504c4448 + ('HeaderLength', c_uint32), # Length of the structure in bytes. + ('SpecRevision', c_uint16), # Indicates compliance with a revision of this specification in the BCD format. 7 : 0 - Minor Version / 15 : 8 - Major Version For revision v0.75 the value will be 0x0075. + ('Reserved', c_uint16), # Reserved for future use. + ('Revision', c_uint32), # Revision of the Payload binary. Major.Minor .Revision.Build . The ImageRevision can be decoded as follows: 7 : 0 - Build Number / 15 :8 - Revision / 23 :16 - Minor Version / 31 :24 - Major Version + ('Attribute', c_uint32), # Length of the structure in bytes. + ('Capability', c_uint32), # Length of the structure in bytes. + ('ProducerId', ARRAY(c_uint8, 16)), # Length of the structure in bytes. + ('ImageId', ARRAY(c_uint8, 16)), # Length of the structure in bytes. + ]