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.bur...@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()) > -- _______________________________________________ Openembedded-core mailing list Openembedded-core@lists.openembedded.org http://lists.openembedded.org/mailman/listinfo/openembedded-core