summaryrefslogtreecommitdiffstats
path: root/meta
diff options
context:
space:
mode:
authorRoss Burton <ross.burton@intel.com>2016-11-07 14:11:01 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-11-15 15:19:53 +0000
commit025f917cec255e1f65d8b8b6c37a1a315173ea8c (patch)
treebca367dfa670675fe70318b3dfd958aea0a2682f /meta
parentef1d874c63ad477af2db27eacf889a8c6eb9b566 (diff)
downloadpoky-025f917cec255e1f65d8b8b6c37a1a315173ea8c.tar.gz
lib/oe/qa: handle binaries with segments outside the first 4kb
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. (From OE-Core rev: a66660aa5bb709547ce0b65a4563e4217c3c3d9f) Signed-off-by: Ross Burton <ross.burton@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta')
-rw-r--r--meta/lib/oe/qa.py82
1 files changed, 41 insertions, 41 deletions
diff --git a/meta/lib/oe/qa.py b/meta/lib/oe/qa.py
index fbe719d8ec..22d76dcbcd 100644
--- a/meta/lib/oe/qa.py
+++ b/meta/lib/oe/qa.py
@@ -1,4 +1,4 @@
1import os, struct 1import os, struct, mmap
2 2
3class NotELFFileError(Exception): 3class NotELFFileError(Exception):
4 pass 4 pass
@@ -23,9 +23,9 @@ class ELFFile:
23 EV_CURRENT = 1 23 EV_CURRENT = 1
24 24
25 # possible values for EI_DATA 25 # possible values for EI_DATA
26 ELFDATANONE = 0 26 EI_DATA_NONE = 0
27 ELFDATA2LSB = 1 27 EI_DATA_LSB = 1
28 ELFDATA2MSB = 2 28 EI_DATA_MSB = 2
29 29
30 PT_INTERP = 3 30 PT_INTERP = 3
31 31
@@ -34,51 +34,46 @@ class ELFFile:
34 #print "'%x','%x' %s" % (ord(expectation), ord(result), self.name) 34 #print "'%x','%x' %s" % (ord(expectation), ord(result), self.name)
35 raise NotELFFileError("%s is not an ELF" % self.name) 35 raise NotELFFileError("%s is not an ELF" % self.name)
36 36
37 def __init__(self, name, bits = 0): 37 def __init__(self, name):
38 self.name = name 38 self.name = name
39 self.bits = bits
40 self.objdump_output = {} 39 self.objdump_output = {}
41 40
42 def open(self): 41 # Context Manager functions to close the mmap explicitly
43 if not os.path.isfile(self.name): 42 def __enter__(self):
44 raise NotELFFileError("%s is not a normal file" % self.name) 43 return self
44
45 def __exit__(self, exc_type, exc_value, traceback):
46 self.data.close()
45 47
48 def open(self):
46 with open(self.name, "rb") as f: 49 with open(self.name, "rb") as f:
47 # Read 4k which should cover most of the headers we're after 50 try:
48 self.data = f.read(4096) 51 self.data = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
52 except ValueError:
53 # This means the file is empty
54 raise NotELFFileError("%s is empty" % self.name)
49 55
56 # Check the file has the minimum number of ELF table entries
50 if len(self.data) < ELFFile.EI_NIDENT + 4: 57 if len(self.data) < ELFFile.EI_NIDENT + 4:
51 raise NotELFFileError("%s is not an ELF" % self.name) 58 raise NotELFFileError("%s is not an ELF" % self.name)
52 59
60 # ELF header
53 self.my_assert(self.data[0], 0x7f) 61 self.my_assert(self.data[0], 0x7f)
54 self.my_assert(self.data[1], ord('E')) 62 self.my_assert(self.data[1], ord('E'))
55 self.my_assert(self.data[2], ord('L')) 63 self.my_assert(self.data[2], ord('L'))
56 self.my_assert(self.data[3], ord('F')) 64 self.my_assert(self.data[3], ord('F'))
57 if self.bits == 0: 65 if self.data[ELFFile.EI_CLASS] == ELFFile.ELFCLASS32:
58 if self.data[ELFFile.EI_CLASS] == ELFFile.ELFCLASS32: 66 self.bits = 32
59 self.bits = 32 67 elif self.data[ELFFile.EI_CLASS] == ELFFile.ELFCLASS64:
60 elif self.data[ELFFile.EI_CLASS] == ELFFile.ELFCLASS64: 68 self.bits = 64
61 self.bits = 64
62 else:
63 # Not 32-bit or 64.. lets assert
64 raise NotELFFileError("ELF but not 32 or 64 bit.")
65 elif self.bits == 32:
66 self.my_assert(self.data[ELFFile.EI_CLASS], ELFFile.ELFCLASS32)
67 elif self.bits == 64:
68 self.my_assert(self.data[ELFFile.EI_CLASS], ELFFile.ELFCLASS64)
69 else: 69 else:
70 raise NotELFFileError("Must specify unknown, 32 or 64 bit size.") 70 # Not 32-bit or 64.. lets assert
71 raise NotELFFileError("ELF but not 32 or 64 bit.")
71 self.my_assert(self.data[ELFFile.EI_VERSION], ELFFile.EV_CURRENT) 72 self.my_assert(self.data[ELFFile.EI_VERSION], ELFFile.EV_CURRENT)
72 73
73 self.sex = self.data[ELFFile.EI_DATA] 74 self.endian = self.data[ELFFile.EI_DATA]
74 if self.sex == ELFFile.ELFDATANONE: 75 if self.endian not in (ELFFile.EI_DATA_LSB, ELFFile.EI_DATA_MSB):
75 raise NotELFFileError("self.sex == ELFDATANONE") 76 raise NotELFFileError("Unexpected EI_DATA %x" % self.endian)
76 elif self.sex == ELFFile.ELFDATA2LSB:
77 self.sex = "<"
78 elif self.sex == ELFFile.ELFDATA2MSB:
79 self.sex = ">"
80 else:
81 raise NotELFFileError("Unknown self.sex")
82 77
83 def osAbi(self): 78 def osAbi(self):
84 return self.data[ELFFile.EI_OSABI] 79 return self.data[ELFFile.EI_OSABI]
@@ -90,16 +85,20 @@ class ELFFile:
90 return self.bits 85 return self.bits
91 86
92 def isLittleEndian(self): 87 def isLittleEndian(self):
93 return self.sex == "<" 88 return self.endian == ELFFile.EI_DATA_LSB
94 89
95 def isBigEndian(self): 90 def isBigEndian(self):
96 return self.sex == ">" 91 return self.endian == ELFFile.EI_DATA_MSB
92
93 def getStructEndian(self):
94 return {ELFFile.EI_DATA_LSB: "<",
95 ELFFile.EI_DATA_MSB: ">"}[self.endian]
97 96
98 def getShort(self, offset): 97 def getShort(self, offset):
99 return struct.unpack_from(self.sex+"H", self.data, offset)[0] 98 return struct.unpack_from(self.getStructEndian() + "H", self.data, offset)[0]
100 99
101 def getWord(self, offset): 100 def getWord(self, offset):
102 return struct.unpack_from(self.sex+"i", self.data, offset)[0] 101 return struct.unpack_from(self.getStructEndian() + "i", self.data, offset)[0]
103 102
104 def isDynamic(self): 103 def isDynamic(self):
105 """ 104 """
@@ -118,7 +117,7 @@ class ELFFile:
118 117
119 def machine(self): 118 def machine(self):
120 """ 119 """
121 We know the sex stored in self.sex and we 120 We know the endian stored in self.endian and we
122 know the position 121 know the position
123 """ 122 """
124 return self.getShort(ELFFile.E_MACHINE) 123 return self.getShort(ELFFile.E_MACHINE)
@@ -166,6 +165,7 @@ def elf_machine_to_string(machine):
166 165
167if __name__ == "__main__": 166if __name__ == "__main__":
168 import sys 167 import sys
169 elf = ELFFile(sys.argv[1]) 168
170 elf.open() 169 with ELFFile(sys.argv[1]) as elf:
171 print(elf.isDynamic()) 170 elf.open()
171 print(elf.isDynamic())