summaryrefslogtreecommitdiffstats
path: root/meta/lib/oe/qa.py
diff options
context:
space:
mode:
Diffstat (limited to 'meta/lib/oe/qa.py')
-rw-r--r--meta/lib/oe/qa.py111
1 files changed, 68 insertions, 43 deletions
diff --git a/meta/lib/oe/qa.py b/meta/lib/oe/qa.py
index 75e7df8546..21066c4dc3 100644
--- a/meta/lib/oe/qa.py
+++ b/meta/lib/oe/qa.py
@@ -1,4 +1,8 @@
-import os, struct
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+import os, struct, mmap
class NotELFFileError(Exception):
pass
@@ -23,9 +27,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 +38,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 +89,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 +121,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)
@@ -130,11 +133,11 @@ class ELFFile:
if cmd in self.objdump_output:
return self.objdump_output[cmd]
- objdump = d.getVar('OBJDUMP', True)
+ objdump = d.getVar('OBJDUMP')
env = os.environ.copy()
env["LC_ALL"] = "C"
- env["PATH"] = d.getVar('PATH', True)
+ env["PATH"] = d.getVar('PATH')
try:
bb.note("%s %s %s" % (objdump, cmd, self.name))
@@ -144,8 +147,30 @@ class ELFFile:
bb.note("%s %s %s failed: %s" % (objdump, cmd, self.name, e))
return ""
+def elf_machine_to_string(machine):
+ """
+ Return the name of a given ELF e_machine field or the hex value as a string
+ if it isn't recognised.
+ """
+ try:
+ return {
+ 0x02: "SPARC",
+ 0x03: "x86",
+ 0x08: "MIPS",
+ 0x14: "PowerPC",
+ 0x28: "ARM",
+ 0x2A: "SuperH",
+ 0x32: "IA-64",
+ 0x3E: "x86-64",
+ 0xB7: "AArch64",
+ 0xF7: "BPF"
+ }[machine]
+ except:
+ return "Unknown (%s)" % repr(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())