[OE-core] [PATCH][morty] lib/oe/qa: handle binaries with segments outside the first 4kb
akuster808
akuster808 at gmail.com
Sat Nov 26 15:39:25 UTC 2016
On 11/25/2016 09:35 AM, Ross Burton wrote:
> The ELF parser was assuming that the segment tables are in the first 4kb of the
> binary. Whilst this generally appears to be the case, there have been instances
> where the segment table is elsewhere (offset 2MB, in this sample I have). Solve
> this problem by mmap()ing the file instead.
>
> Also clean up the code a little whilst chasing the problem.
merged to staging.
Armin
>
> Signed-off-by: Ross Burton <ross.burton at intel.com>
> ---
> meta/lib/oe/qa.py | 82 +++++++++++++++++++++++++++----------------------------
> 1 file changed, 41 insertions(+), 41 deletions(-)
>
> diff --git a/meta/lib/oe/qa.py b/meta/lib/oe/qa.py
> index fbe719d..22d76dc 100644
> --- a/meta/lib/oe/qa.py
> +++ b/meta/lib/oe/qa.py
> @@ -1,4 +1,4 @@
> -import os, struct
> +import os, struct, mmap
>
> class NotELFFileError(Exception):
> pass
> @@ -23,9 +23,9 @@ class ELFFile:
> EV_CURRENT = 1
>
> # possible values for EI_DATA
> - ELFDATANONE = 0
> - ELFDATA2LSB = 1
> - ELFDATA2MSB = 2
> + EI_DATA_NONE = 0
> + EI_DATA_LSB = 1
> + EI_DATA_MSB = 2
>
> PT_INTERP = 3
>
> @@ -34,51 +34,46 @@ class ELFFile:
> #print "'%x','%x' %s" % (ord(expectation), ord(result), self.name)
> raise NotELFFileError("%s is not an ELF" % self.name)
>
> - def __init__(self, name, bits = 0):
> + def __init__(self, name):
> self.name = name
> - self.bits = bits
> self.objdump_output = {}
>
> - def open(self):
> - if not os.path.isfile(self.name):
> - raise NotELFFileError("%s is not a normal file" % self.name)
> + # Context Manager functions to close the mmap explicitly
> + def __enter__(self):
> + return self
> +
> + def __exit__(self, exc_type, exc_value, traceback):
> + self.data.close()
>
> + def open(self):
> with open(self.name, "rb") as f:
> - # Read 4k which should cover most of the headers we're after
> - self.data = f.read(4096)
> + try:
> + self.data = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
> + except ValueError:
> + # This means the file is empty
> + raise NotELFFileError("%s is empty" % self.name)
>
> + # Check the file has the minimum number of ELF table entries
> if len(self.data) < ELFFile.EI_NIDENT + 4:
> raise NotELFFileError("%s is not an ELF" % self.name)
>
> + # ELF header
> self.my_assert(self.data[0], 0x7f)
> self.my_assert(self.data[1], ord('E'))
> self.my_assert(self.data[2], ord('L'))
> self.my_assert(self.data[3], ord('F'))
> - if self.bits == 0:
> - if self.data[ELFFile.EI_CLASS] == ELFFile.ELFCLASS32:
> - self.bits = 32
> - elif self.data[ELFFile.EI_CLASS] == ELFFile.ELFCLASS64:
> - self.bits = 64
> - else:
> - # Not 32-bit or 64.. lets assert
> - raise NotELFFileError("ELF but not 32 or 64 bit.")
> - elif self.bits == 32:
> - self.my_assert(self.data[ELFFile.EI_CLASS], ELFFile.ELFCLASS32)
> - elif self.bits == 64:
> - self.my_assert(self.data[ELFFile.EI_CLASS], ELFFile.ELFCLASS64)
> + if self.data[ELFFile.EI_CLASS] == ELFFile.ELFCLASS32:
> + self.bits = 32
> + elif self.data[ELFFile.EI_CLASS] == ELFFile.ELFCLASS64:
> + self.bits = 64
> else:
> - raise NotELFFileError("Must specify unknown, 32 or 64 bit size.")
> + # Not 32-bit or 64.. lets assert
> + raise NotELFFileError("ELF but not 32 or 64 bit.")
> self.my_assert(self.data[ELFFile.EI_VERSION], ELFFile.EV_CURRENT)
>
> - self.sex = self.data[ELFFile.EI_DATA]
> - if self.sex == ELFFile.ELFDATANONE:
> - raise NotELFFileError("self.sex == ELFDATANONE")
> - elif self.sex == ELFFile.ELFDATA2LSB:
> - self.sex = "<"
> - elif self.sex == ELFFile.ELFDATA2MSB:
> - self.sex = ">"
> - else:
> - raise NotELFFileError("Unknown self.sex")
> + self.endian = self.data[ELFFile.EI_DATA]
> + if self.endian not in (ELFFile.EI_DATA_LSB, ELFFile.EI_DATA_MSB):
> + raise NotELFFileError("Unexpected EI_DATA %x" % self.endian)
>
> def osAbi(self):
> return self.data[ELFFile.EI_OSABI]
> @@ -90,16 +85,20 @@ class ELFFile:
> return self.bits
>
> def isLittleEndian(self):
> - return self.sex == "<"
> + return self.endian == ELFFile.EI_DATA_LSB
>
> def isBigEndian(self):
> - return self.sex == ">"
> + return self.endian == ELFFile.EI_DATA_MSB
> +
> + def getStructEndian(self):
> + return {ELFFile.EI_DATA_LSB: "<",
> + ELFFile.EI_DATA_MSB: ">"}[self.endian]
>
> def getShort(self, offset):
> - return struct.unpack_from(self.sex+"H", self.data, offset)[0]
> + return struct.unpack_from(self.getStructEndian() + "H", self.data, offset)[0]
>
> def getWord(self, offset):
> - return struct.unpack_from(self.sex+"i", self.data, offset)[0]
> + return struct.unpack_from(self.getStructEndian() + "i", self.data, offset)[0]
>
> def isDynamic(self):
> """
> @@ -118,7 +117,7 @@ class ELFFile:
>
> def machine(self):
> """
> - We know the sex stored in self.sex and we
> + We know the endian stored in self.endian and we
> know the position
> """
> return self.getShort(ELFFile.E_MACHINE)
> @@ -166,6 +165,7 @@ def elf_machine_to_string(machine):
>
> if __name__ == "__main__":
> import sys
> - elf = ELFFile(sys.argv[1])
> - elf.open()
> - print(elf.isDynamic())
> +
> + with ELFFile(sys.argv[1]) as elf:
> + elf.open()
> + print(elf.isDynamic())
>
More information about the Openembedded-core
mailing list